Code Monkey home page Code Monkey logo

notionapi's Introduction

About notionapi

This is an unofficial, Go API for https://notion.so. Mostly for reading, limited write capabilities.

It allows you to retrieve content of a Notion page in structured format.

You can then e.g. convert that format to HTML.

Note: official Notion API is still in beta and not as capable as this unofficial API.

Documentation:

You can learn how I reverse-engineered the Notion API in order to write this library.

Real-life usage

I use this API to publish my blog and series of programming books from content stored in Notion.

Notion serves as a CMS (Content Management System). I write and edit pages in Notion.

I use custom Go program to download Notion pages using this this library and converts pages to HTML. It then publishes the result to Netlify.

You can see the code at https://github.com/kjk/blog and https://github.com/essentialbooks/tools/

Implementations for other languages

notionapi's People

Contributors

5hay avatar apenwarr avatar auxesis avatar caarlos0 avatar dependabot[bot] avatar ethanthatonekid avatar kjk avatar krapshsa avatar moul avatar nerorenaissance avatar nmcclain avatar osbre avatar shijianzhiwai avatar simonswine avatar ymatzki avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

notionapi's Issues

nvm

got it fixed ty

Verbose flag doesn't work for `do -to-html`

Example commands with output:

$ ./do/do.sh -to-html 94167af6567043279811dc923edd1f04

currDirAbs: '/Users/eric/Work/Other/notionapi'
NOTION_TOKEN env variable not set. Can only access public pages
tmpdata/cache/94167af6567043279811dc923edd1f04.2.page.html : HTML version of the page
Opening browser with file:///Users/eric/Work/Other/notionapi/tmpdata/cache/94167af6567043279811dc923edd1f04.2.page.html

$ ./do/do.sh -verbose -to-html 94167af6567043279811dc923edd1f04

currDirAbs: '/Users/eric/Work/Other/notionapi'
NOTION_TOKEN env variable not set. Can only access public pages
tmpdata/cache/94167af6567043279811dc923edd1f04.2.page.html : HTML version of the page
Opening browser with file:///Users/eric/Work/Other/notionapi/tmpdata/cache/94167af6567043279811dc923edd1f04.2.page.html

As you can see the -verbose flag doesn't make any difference

Can toMarkdown supports code type selections?

Hi,
I am using tomarkdown.ToMarkdown api to get markdown content of a certain page.
For code block, it generate markdown as below

     code

instead of

```python
code
```

I wonder if there is anyway to keep coding language attributes like the second one.

Thanks!

502 Bad Gateway

I get this on edge dev, Windows 10. At work. Firewall?

502 Bad Gateway

ExportPages fails with big workspaces

Hi,

I'm currently working on a small utility command line application to export my whole workspace in a scriptable way for backup purposes.

My workspace is probably between 10 to 20 GB. I can't really use the client.ExportPages (Ref) function because of how it's implemented. My server kills the app because this function returns a byte slice that is just too big to handle for my 16 GB RAM server (that also does many other things).

I already forked this project and could send a PR if you don't mind. I just wanted to talk to you first about a possible solution that you're also fine with.
For backwards compatibility reasons you probably don't want to change the behavior of this function.

What I did just for testing: Stop when exportURL (Ref) is filled. Then I can just http.Get that URL and push the response through io.Copy to write into a file.

Unable to download notion page

Hi. @kjk
I followed the instructions in this article to download a Notion page using the Go client, but I encountered an issue.

Steps to Reproduce

I retrieved the Notion access token and set it as an environment variable.
I executed the following code to download a page:

Code

notionToken := os.Getenv("NOTION_ACCESS_TOKEN")
client := &notionapi.Client{}
client.AuthToken = notionToken

page, err := client.DownloadPage(pageID)
if err != nil {
    fmt.Println("Failed to download page")
    log.Fatal(err)
}

Expected Result

The page should be successfully downloaded without any errors.

Actual Result

Failed to download page
2024/07/11 14:31:37 http.Post('https://www.notion.so/api/v3/syncRecordValues') returned non-200 status code of 401

Additional Information

I was able to successfully retrieve table data using the same authorization token, which indicates that the token is valid.

I want to solve it and would like to convert the page's JSON into HTML. If you have any idea to solve it, please remind me. Thanks ๐Ÿ™

Exporting markdown fails

Hi @kjk

We're using your excellent library for one reason -- it has the option of exporting pages with markdown. The official API has no markdown exporting.

Now, this used to work with your notionapi, but a few weeks ago they changed something on their backend and it now fails.

We're using client.ExportPages() which internall use enqueueTask and getTasks and it then returns the download url.

Example code to reproduce the problem:

	client := &notionapi.Client{}

	client.AuthToken = "..."
	client.DebugLog = true

	url, err := client.RequestPageExportURL("...", notionapi.ExportTypeMarkdown, false)
	panicIfErr(err)
	fmt.Println(url)

	res, err := client.DownloadURL(url)
	panicIfErr(err)

	fmt.Println("res:", res.Data)

...and it errors in client.DownloadURL().

We tried to inspect the browser to see why downloading the file there works, and this is the final "download file" request (stripped of all the other unneeded headers):

curl 'https://file.notion.so/....zip?id=...&table=user_export&expirationTimestamp=...&signature=...&download=true&downloadName=....zip' \
  -H 'cookie: file_token=...;' \
  --compressed

So, it looks like, they now require a file_token cookie with file.notion.so. It is not enough to have the download URL.

Any idea how the file_token is retrieved/calculated?

Thank you!

Just wanted to say thank you for creating this library! I wanted to tinker around with the Notion API and finding a Go library was just perfect. โค๏ธ

Also, thank you for publishing a blog post about this. It's always fun to read the line of thought that lead to a project.

Again, just wanted to say thanks. GitHub doesn't really have a way of saying thanks on a repo, so went for creating an issue.

Implement getSignedFileUrls API

ttps://www.notion.so/api/v3/getSignedFileUrls:

{"urls":[{"url":"https://s3-us-west-2.amazonaws.com/secure.notion-static.com/6077c30b-6aba-4805-a64c-c78514f87823/untitled"}]}

response:

{"signedUrls":["https://s3.us-west-2.amazonaws.com/secure.notion-static.com/6077c30b-6aba-4805-a64c-c78514f87823/untitled?AWSAccessKeyId=ASIAT73L2G45M3SUQFM7&Expires=1553074461&Signature=s9BedA%2FCjkS7YarzvdDJjjaXjJ8%3D&x-amz-security-token=FQoGZXIvYXdzEKf%2F%2F%2F%2F%2F%2F%2F%2F%2F%2FwEaDAHrxOMi7f5QmzW0xSK3A5UWyz0IFDXcISwrjGsr5D83qr8orK4kmwa1mlma%2BErs3ydqWlG5ltZgzR6Gq8aYjRN2lHH%2FV2BrlIV30p8dUOamGOFZqMzo1cIXAuZNG2eJhvKgA%2BX%2FXUWnwpa0BIQJnU%2FAhkrvC94731WQHMwcTK7zWuhktes43RHjvPBNYgwMuP6qax6RjyU5MDP5NY5bPLFzV1LVSsGdLFMpO9EKYJd4J1db%2Bnc4gTW4%2BYXqselq6zUfU80uwPTFcQYl4aMvB7vRs2GhA5WmA9tOX%2BLxmjXFeYq%2FC931EBpQs9XS22dxfLsT35K6HnmvhBU9M4URNmFTXmaAOXoUYakMhRib4OhsHunee%2Fa2Uy5KmSC%2B3YPaYAqOVIyTbjXFE0WV%2BiRnhUDXr6eEEzoSztE7oIj9BDAUEffOOkH75WbPPUy%2BFRS8WQ81VZbfogAkCm6JhpT7o%2FnnSNOmDF1gMB0%2FuHp42sF5IJP8cTZTMRrRyWaIyiv%2FggYQHRzywsgoS13HOznOJOfkrzGw8PwJZ3Ehg2zPTZvsbXJotZq1FNkPpbMJN2LwpBcwnO%2BBm4DWs55vCWz2ef2vY9TzwtAouYPC5AU%3D"]}

Sample page: https://www.notion.so/Sumatra-online-notes-d44593a5a7aa4265a51e845c80560847

Nested filters

Hi,
thanks for your outstanding work with this unofficial API !

But I find out that Notion team has improve the way to handle filters to add filter groups, since 28/05.
Change log - Feature

This new way seems to break the actual filters structure
so I update locally the query_collection.go to make it work

Add two new types

// query_collection.go

// Query2FilterGroup describes the filtering of a query
type Query2FilterGroup struct {
	Filter   *Query2Filter        `json:"filter"`
	Filters  []*Query2FilterGroup `json:"filters"`
	Operator string               `json:"operator"`
	Property string               `json:"property"`
}

// Query2Filter describes the filtering of a query
type Query2Filter struct {
	Operator string      `json:"operator"`
	ID       string      `json:"id"` // not sure it is still used
	Property string      `json:"property"`
	Type     string      `json:"type"` // not sure it is still used
	Value    interface{} `json:"value"` // not typed properly
}

Update the Query type

// query_collection.go

// Query describes a query
type Query struct {
	Aggregate  []*AggregateQuery `json:"aggregate"`
	GroupBy    interface{}       `json:"group_by"`
	CalendarBy interface{}       `json:"calendar_by"`

	FilterOperator string             `json:"filter_operator"`
	Filter         *Query2FilterGroup `json:"filter"`
	Sort           []*QuerySort       `json:"sort"`
}

I am not sure if this is a definitive way to handle QueryFilters because the query is now called query2 in CollectionViews

so update the collectionview too

// collection.go

// CollectionView represents a collection view
type CollectionView struct {
	ID          string       `json:"id"`
	Version     int64        `json:"version"`
	Type        string       `json:"type"` // "table"
	Format      *FormatTable `json:"format"`
	Name        string       `json:"name"`
	ParentID    string       `json:"parent_id"`
	ParentTable string       `json:"parent_table"`
	Query       *Query       `json:"query"`
	Query2      *Query       `json:"query2"`
	Alive       bool         `json:"alive"`
	PageSort    []string     `json:"page_sort"`

	// set by us
	RawJSON map[string]interface{} `json:"-"`
}

This changes are working locally even if it is not fully typed.

client := &notionapi.Client{}
client.AuthToken = "token"

collectionID := "collectionID"
collectionViewID := "collectionViewID
preflightResp, err := client.QueryCollection(collectionID, collectionViewID, &notionapi.Query{}, &notionapi.User{})
if err != nil {
	log.Fatalf("QueryCollection() failed with %s\n", err)
}
resp, _ := client.QueryCollection(collectionID, collectionViewID, preflightResp.RecordMap.CollectionViews[collectionViewID].CollectionView.Query2, &notionapi.User{})

I post it here because of the questions

Favour to ask: Commandline wrapper

Hello, let me say thank you for your work.

Sadly, I am a python programmer too busy to learn go just because I want to use this module. Could you please provide simple commandline wrapper? It would allow to other non-go programmers use this project.

You mentioned notion_import.go and notion_to_html.go, but I was unable to put it all together. I think just simple commandline wrapper over these two would do.

BlockRecords not populated

After downloading a (private) page, accessing page.BlockRecords yields an empty slice. However, page.ForEachBlock() still yields the expected result. Is this intentional, or a bug?

Minimal example:

client := &notionapi.Client{AuthToken: authToken}
page := client.DownloadPage(pageID)
// page.BlockRecords = []

panic: unexpected attribute 'm'

Hi!

I forked your version, adjusted the Page IDs and tried to download a page with subpages.
I received the following error:

Page    1 ****: downloaded. Title: Development
Download **** failed with 'unexpected attribute 'm''
Download **** failed with 'unexpected attribute 'm''
panic: unexpected attribute 'm'

goroutine 1 [running]:
main.panicIfErr(...)
	/Users/boni/Documents/Programmieren/Web/Notion2Confluence/util.go:21
main.loadNotionPages(0xc000092340, 0x13d497e, 0x20, 0xc000130030, 0x1786000)
	/Users/boni/Documents/Programmieren/Web/Notion2Confluence/import.go:381 +0x47c
main.loadAllPages(0xc000092340, 0xc0005d1df8, 0x1, 0x1, 0xc00001a000, 0xc00012e108)
	/Users/boni/Documents/Programmieren/Web/Notion2Confluence/import.go:395 +0xb0
main.loadArticles(0xc000092340, 0x1dcee7)

Looking at the log I think it might be the discussion + comments that are on one of those pages:

 "discussion": {
      "a70a81be-6ab5-4a87-b716-c79624f8adb8": {
        "role": "editor",
        "value": {
          "comments": [
            "a087e43b-cc18-4843-9e02-8e330c17627d",
            "0f769e08-4642-4df8-92d7-874dd7627a8f"
          ],
          "context": [
            [
              "TODO",
              [
                [
                  "m",
                  "a70a81be-6ab5-4a87-b716-c79624f8adb8"
                ]
              ]
            ]
          ],
          "id": "a70a81be-6ab5-4a87-b716-c79624f8adb8",
          "parent_id": "098cc82b-fa71-4746-b67b-26e618192526",
          "parent_table": "block",
          "resolved": false,
          "version": 2
        }
      }
    },

Allow supplying a custom *http.Client

This would allow folks to pass the token header correctly.

This probably implies changing the api a bit. It's pretty common to have a Client type and a corresponding NewClient constructor.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.