Notion API 介绍

Notion的页面组织结构非常灵活,但是一直没有找到相关介绍,最近了解到一个使用Notion作为后台CMS的项目,浏览了一下源码和Notion API。通过API也能大致了解下官方开放的能力以及相关数据结构。

pages


page内容主要由两部分构成

https://files.readme.io/369b6a5-page-properties-and-content.png

  1. page properties
  • 指定page的基础信息,基础数据结构详见文档,包括:

    type Page struct {
    Object ObjectType `json:"object"`
    ID ObjectID `json:"id"`
    CreatedTime time.Time `json:"created_time"`
    LastEditedTime time.Time `json:"last_edited_time"`
    CreatedBy User `json:"created_by,omitempty"`
    LastEditedBy User `json:"last_edited_by,omitempty"`
    Archived bool `json:"archived"`
    Properties Properties `json:"properties"`
    Parent Parent `json:"parent"`
    URL string `json:"url"`
    PublicURL string `json:"public_url"`
    Icon *Icon `json:"icon,omitempty"`
    Cover *Image `json:"cover,omitempty"`
    }

所有的page都有一个parent,当其parent为database时(也就是当前page为db中的一条记录时), properties 格式与db的property格式一致。否则 properties 仅包含一个title属性。

  1. page content

一个页面的内容由多个块(block)组成。这些块被称为页面的子块。每个块都有一个类型,例如段落(paragraph)、标题(heading)或图像(image)。某些类型的块,例如切换列表(toggle list),还有自己的子块。

段落块(Paragraph blocks)是文档结构中的一个基本组成单元,block具有一些通用的属性,包括:

type BasicBlock struct {
Object ObjectType `json:"object"` // 通常为block
ID BlockID `json:"id,omitempty"`
Type BlockType `json:"type"` // 比如heading_1、image、quote、pdf等
CreatedTime *time.Time `json:"created_time,omitempty"`
LastEditedTime *time.Time `json:"last_edited_time,omitempty"`
CreatedBy *User `json:"created_by,omitempty"`
LastEditedBy *User `json:"last_edited_by,omitempty"`
HasChildren bool `json:"has_children,omitempty"`
Archived bool `json:"archived,omitempty"`
Parent *Parent `json:"parent,omitempty"`
}

除此之外,块还包含了一些特定于其类型的属性,这些属性存储在“paragraph”属性中,其内容与具体的block type有关,具体见文档

以todo block类型为例,paragraph的内容格式如下:

{
"object": "block",
"id": "380c78c0-e0f5-4565-bdbd-c4ccb079050d",
"type": "paragraph",
"created_time": "",
"last_edited_time": "",
"has_children": true,

"paragraph": {
"text": [/* details omitted */],
"children": [
{
"object": "block",
"id": "6d5b2463-a1c1-4e22-9b3b-49b3fe7ad384",
"type": "to_do",
"created_time": "",
"last_edited_time": "",
"has_children": false,

"to_do": {
"text": [/* details omitted */],
"checked": false
}
}
]
}
}
  • 很多block type支持嵌套,故API返回的block列表并非扁平化的数据。而是存在多级嵌套关系。
  • 还有unsupported类型的block type
  • 许多块类型支持富文本。在支持的情况下,块类型对象将包含一个 rich_text 对象。所有 rich_text 对象都将包含一个 plain_text 属性,这为开发人员从 Notion 块中访问未格式化的文本提供了一种方便的方法。

page相关接口包括:

接口名 HTTP Method URL 功能说明
https://developers.notion.com/reference/post-page POST https://api.notion.com/v1/pages 创建page,parent只能是一个已存在page或database。不包括page内容。
增加内容只能通过https://developers.notion.com/reference/patch-block-children接口
https://developers.notion.com/reference/retrieve-a-page GET https://api.notion.com/v1/pages/{page_id} 取page的属性property,不包括content。
property数量限制在25个。如果超过25,使用下面的接口。
如果page的parent是db类型,property信息与db的property schema一致。
https://developers.notion.com/reference/retrieve-a-page-property GET https://api.notion.com/v1/pages/{page_id}/properties/{property_id} 根据page_id和property_id取property(列表)信息。支持分页,用于property大于25的场景。
https://developers.notion.com/reference/patch-page PATCH https://api.notion.com/v1/pages/{page_id} 支持更新parent为db类型page的property值(即更新db中的某条记录)。
也可以更新任意page类型的icon、cover、archive等公共属性。

block相关的接口包括:

接口名 HTTP Method URL 功能说明
https://developers.notion.com/reference/patch-block-children PATCH https://api.notion.com/v1/blocks/{block_id}/children 为block、page、db增加子block。
api限制每次最多新增100个block。对于有child类型的block,api限制在单词请求中存在最高2层的child block嵌套。
https://developers.notion.com/reference/retrieve-a-block GET https://api.notion.com/v1/blocks/{block_id} 取一个block的数据。如果has_children为true,使用retrieve block child接口取其children信息。// 感觉有点鸡肋
https://developers.notion.com/reference/get-block-children GET https://api.notion.com/v1/blocks/{block_id}/children 翻页的方式取block的children列表。https://developers.notion.com/docs/working-with-page-content#modeling-content-as-blocks也是通过block list来组织的。
仅返回第一级的children,如果children也有嵌套的子block需要通过api递归获取。
https://developers.notion.com/reference/update-a-block PATCH https://api.notion.com/v1/blocks/{block_id} 更新block_id的内容。
https://developers.notion.com/reference/delete-a-block DELETE https://api.notion.com/v1/blocks/{block_id} 删除block

databases


数据库是 Notion 工作区中的page集合,可以根据需要过滤、排序和组织。允许用户在 Notion 中创建和操作结构化数据。

目前public API不支持两种db:Linked databases、Wiki databases

database数据结构:

type Database struct {
Object ObjectType `json:"object"` // database
ID ObjectID `json:"id"` // "2f26ee68-df30-4251-aad4-8ddc420cba3d"
CreatedTime time.Time `json:"created_time"`
LastEditedTime time.Time `json:"last_edited_time"`
CreatedBy User `json:"created_by,omitempty"`
LastEditedBy User `json:"last_edited_by,omitempty"`
Title []RichText `json:"title"` // [/* details omitted */],
Parent Parent `json:"parent"`
URL string `json:"url"`
PublicURL string `json:"public_url"`
**// Properties is a map of property configurations that defines what Page.Properties each page of the database can use**
Properties PropertyConfigs `json:"properties"` // {/* a collection of property objects */},
Description []RichText `json:"description"` // [/* details omitted */],
IsInline bool `json:"is_inline"`
Archived bool `json:"archived"`
Icon *Icon `json:"icon,omitempty"`
Cover *Image `json:"cover,omitempty"`
}

properties 中存储DB字段相关定义map,key为字段名称,value为字段属性object,其定义与属性字段类型相关。

{
"object": "database",

"properties": {
"Grocery item": {
"id": "fy:{",
"type": "title",
"title": {}
},
"Price": {
"id": "dia[",
"type": "number",
"number": {
"format": "dollar"
}
},
"Last ordered": {
"id": "]\\R[",
"type": "date",
"date": {}
},
}

// remaining details omitted
}
  • 属性类型 title 比较特殊,每个db都有一个具有title类型的属性。这种类型的属性是指数据库中每个项目的页面标题。
  • 类型的值对应于属性对象中的另一个键。每个属性对象都有一个与其类型值相同的嵌套属性。例如,“Last ordered”的类型为“date”,并且它还有一个date属性。这种模式在许多对象上都使用了Notion API,我们称之为特定类型的数据。
  • 某些属性对象类型具有额外的配置。例如,Price的类型为“number”。Number属性对象在number属性内部具有额外的配置。在此示例中,格式配置设置为“美元”,以控制此列中页面属性值的外观。

新增page到DB

向db中插入一个page时,需要指定其属性定义与db属性定义一致,同时parent信息为database的id。

curl -X POST https://api.notion.com/v1/pages \
-H 'Authorization: Bearer '"$NOTION_API_KEY"'' \
-H "Content-Type: application/json" \
-H "Notion-Version: 2022-06-28" \
--data '{
"parent": { "type": "database_id", "database_id": "2f26ee68-df30-4251-aad4-8ddc420cba3d" },
"properties": {
"Grocery item": {
"type": "title",
"title": [{ "type": "text", "text": { "content": "Tomatoes" } }]
},
"Price": {
"type": "number",
"number": 1.49
},
"Last ordered": {
"type": "date",
"date": { "start": "2021-05-11" }
}
}
}'

注意:组织上面的properties数据结构比较麻烦,容易出错。所以更好的方案是在构造page记录前使用database的retrieve接口,先获取到db的properties数据结构后再填充相关字段值。

插入page成功后会返回对应的pageid,这时再使用pageid填充block内容即可。

查询db

通过Query接口可以查询db中的部分page。

  • filter 用于指定查询条件,多个条件可以相互组合。格式

客户端中的filter设置

客户端中的filter设置

{
"filter":{
"and":[
{
"property":"Done",
"checkbox":{
"equals":true
}
},
{
"or":[
{
"property":"Tags",
"contains":"A"
},
{
"property":"Tags",
"contains":"B"
}
]
}
]
}
}
{
"sorts": [
{
"property": "Food group",
"direction": "descending"
},
{
"property": "Name",
"direction": "ascending"
}
]
}

查询接口返回db中已过滤&排序的page数组,格式大致如下:

{
"object": "list",
"results": [
{
"object": "page",
/* details omitted */
}
],
"has_more": false,
"next_cursor": null
}
  • 仅返回page信息,不包括其block内容。
  • 通过翻页方式返回,每次最大返回100条page。
  • 如果需要遍历所有记录,需通过 start_cursorpage_size 参数指定翻页条件

files and media


  • notion优先推荐将文件存储到外部系统,以链接的方式插入db或page。(每个page的大小限制为10M?)

  • notion也提供了文件上传能力,将文件存储在notion的s3实例中提供访问。

    • 文件上传目前notion API不支持,只能通过客户端上传
    • 当通过page或db的接口读取到文件的url后,可以通过url下载文件。url只有1个小时的有效期,具体过期时间通过expiry_time指定。
    {
    "url": "https://s3.us-west-2.amazonaws.com/secure.notion-static.com/9bc6c6e0-32b8-4d55-8c12-3ae931f43a01/brocolli.jpeg?...",
    "expiry_time": "2020-03-17T19:10:04.968Z"
    }

database相关的接口

接口名 HTTP Method URL 功能说明
https://developers.notion.com/reference/create-a-database POST https://api.notion.com/v1/databases 在指定的(parent)page插入一个db,同时需要指定db的属性schema(property)。parent只能是page或者wiki database类型。
https://developers.notion.com/reference/post-database-query POST https://api.notion.com/v1/databases/{database_id}/query 分页获取db中的page记录列表,可以通过filter、sort指定查询条件。
https://developers.notion.com/reference/retrieve-a-database GET https://api.notion.com/v1/databases/{database_id} 获取https://developers.notion.com/reference/database,包括db基础信息以及properties字段。
https://developers.notion.com/reference/update-a-database PATCH https://api.notion.com/v1/databases/{database_id} 更新db对象,包括title、description或者properties

comments


notion支持两种形态的comment,对page的评论和对文本内容(block)的评论。

通过API访问时需要有page对应的comment权限,包括:

  1. Read comments.
  2. Write (or insert) comments.

使用公共API可以实现:

  • 给页面添加评论。
  • 对内联评论做出回应(即向现有讨论线程添加评论)。
  • 读取一个块或页面上开放(”open” or “un-resolved”)的评论。

不支持的点:

  • 启动新的讨论线程。
  • 编辑现有的评论。
  • 检索已解决(resolved)的评论。

读取page或者block的评论

请求方式:

curl 'https://api.notion.com/v1/comments?block_id=5c6a28216bb14a7eb6e1c50111515c3d'\
-H 'Authorization: Bearer '"$NOTION_API_KEY"'' \
-H "Notion-Version: 2022-06-28"

应答格式详见文档

增加评论

重点参数为parent(page或者block)、rich-text