Notion API 开发:以文档为数据库
1. 认识 Notion API:为什么把文档当数据库
1.1 传统开发与 Notion 数据库的碰撞
在常规 Web 开发中,我们习惯使用 MySQL、PostgreSQL 或 MongoDB 来存储结构化数据。而 Notion 早已不仅仅是一个笔记工具,它内置了**数据库(Database)**功能,支持属性、筛选、排序等。通过 Notion API,我们可以直接将一个 Notion 数据库当作应用的后台数据源,实现原型搭建、小型后台管理甚至自动化流程。
1.2 以文档为数据库的核心优势
- 零部署成本:无需购买服务器安装数据库,只需在 Notion 页面中设计好数据库属性。
- 可视化编辑:团队成员可以直接在 Notion 中修改数据,无需开发后台管理界面。
- 快速迭代:适合 MVP 开发、内容管理、用户反馈收集等场景。
本教程将带你从零搭建开发环境,通过实操掌握 Notion API 的读写、过滤与排序,最终完成一个“以文档为数据库”的简单留言板应用。
2. 准备工作:获取 API 令牌与创建数据库
2.1 创建 Notion 集成(Integration)
- 打开 Notion 开发者页面,点击“新建集成”。
- 输入名称(如“我的留言板”),选择关联的工作区,点击“提交”。
- 复制生成的 Internal Integration Secret,它类似于数据库密码,请妥善保存。
2.2 为数据库授权集成
Notion 的授权粒度是页面级:
- 在 Notion 工作区中新建一个页面,标题为“留言板”。
- 在页面内添加一个数据库 - 行内(也可以使用整页数据库),命名为“留言列表”。
- 给数据库添加以下属性:
- 名称(标题栏,默认属性)
- 内容(文本)
- 创建时间(创建时间)
- 点击页面右上角的“···”,选择“连接”,找到你刚创建的集成,点击连接。这样集成才有权访问该数据库。
2.3 获取数据库 ID
数据库 URL 通常为 https://www.notion.so/workspace/数据库名称?v=xxx,你需要截取中间的一串 32 位字符(不带 ?v= 部分),它就是数据库 ID。例如:
https://www.notion.so/xxxx/1234567890abcdef...?v=... 中的 1234567890abcdef... 就是 ID。
3. 环境搭建与第一次请求
3.1 选择你熟悉的开发语言
Notion API 基于 REST,任何能发送 HTTP 请求的语言均可使用。本教程以 Node.js + JavaScript 为例,当然你也可以使用 Python、cURL 等。
初始化项目:
mkdir notion-demo && cd notion-demo
npm init -y
npm install @notionhq/client dotenv
创建 .env 文件:
NOTION_TOKEN=你的集成密钥
NOTION_DATABASE_ID=你的数据库ID
3.2 用 Notion SDK 查询数据库
创建 index.js:
const { Client } = require("@notionhq/client");
require("dotenv").config();
const notion = new Client({ auth: process.env.NOTION_TOKEN });
const databaseId = process.env.NOTION_DATABASE_ID;
async function getEntries() {
const response = await notion.databases.query({ database_id: databaseId });
// 提取每个条目的名称和内容
const entries = response.results.map((page) => {
const props = page.properties;
const title = props["名称"]?.title[0]?.text?.content || "无标题";
const content = props["内容"]?.rich_text[0]?.text?.content || "";
return { title, content, id: page.id };
});
console.log(entries);
}
getEntries().catch(console.error);
运行 node index.js,即可在终端看到数据库中所有条目。这证明你已经成功将 Notion 数据库当作数据源读取。
4. 数据库的核心操作:增删改查
4.1 创建新条目(CREATE)
向留言板添加新留言,即创建数据库页面:
async function addEntry(name, contentText) {
await notion.pages.create({
parent: { database_id: databaseId },
properties: {
"名称": { title: [{ text: { content: name } }] },
"内容": { rich_text: [{ text: { content: contentText } }] }
}
});
console.log("添加成功");
}
属性名(如“名称”“内容”)必须与数据库中的列名严格一致。
4.2 更新条目(UPDATE)
根据页面 ID 修改内容:
async function updateEntry(pageId, newContent) {
await notion.pages.update({
page_id: pageId,
properties: {
"内容": { rich_text: [{ text: { content: newContent } }] }
}
});
}
4.3 删除条目(删除/归档)
Notion API 支持归档页面,相当于软删除:
async function deleteEntry(pageId) {
await notion.pages.update({
page_id: pageId,
archived: true
});
}
归档后的条目依然存留,可在 Notion 中手动恢复。
4.4 按条件查询与排序
利用数据库查询参数实现精确筛选:
async function filterByKeyword(keyword) {
const response = await notion.databases.query({
database_id: databaseId,
filter: {
property: "内容",
rich_text: { contains: keyword }
},
sorts: [{ property: "创建时间", direction: "descending" }]
});
// 处理结果...
}
filter支持文本、数字、日期等多种类型。sorts支持多列排序。
5. 属性类型的处理要点
5.1 标题(title)与富文本(rich_text)
- 标题属性为
title数组,需要results[0].title[0].text.content。 - 富文本同样为
rich_text数组,内容可能分片,建议拼接所有片段。
5.2 数字、日期与选项
- 数字:
{ number: 42 } - 日期:
{ date: { start: "2025-04-01" } } - 状态/单选:
{ select: { name: "已完成" } } - 多选:
{ multi_select: [{ name: "标签A" }] }
示例:初始化数据库时可添加“状态”列(单选),并在代码中这样更新:
properties: {
"状态": { select: { name: "待处理" } }
}
6. 实战:构建一个简单的留言板 API
6.1 用 Express 暴露接口
安装 express:
npm install express
创建 server.js:
const express = require("express");
const { getEntries, addEntry } = require("./notion-operations"); // 封装之前的函数
const app = express();
app.use(express.json());
app.get("/messages", async (req, res) => {
const entries = await getEntries();
res.json(entries);
});
app.post("/messages", async (req, res) => {
const { name, content } = req.body;
await addEntry(name, content);
res.status(201).json({ success: true });
});
app.listen(3000, () => console.log("Server running on port 3000"));
这样,前端页面就可以通过 REST 接口读写 Notion 数据库中的留言。
6.2 前端展示与提交(极简版)
一个纯 HTML 示例,直接内嵌于项目:
<!DOCTYPE html>
<html>
<body>
<h2>留言板</h2>
<input id="name" placeholder="昵称">
<textarea id="content"></textarea>
<button onclick="submitMessage()">提交</button>
<ul id="list"></ul>
<script>
async function loadMessages() {
const res = await fetch("/messages");
const data = await res.json();
document.getElementById("list").innerHTML = data
.map(m => `<li><b>${m.title}</b>: ${m.content}</li>`)
.join("");
}
async function submitMessage() {
await fetch("/messages", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
name: document.getElementById("name").value,
content: document.getElementById("content").value
})
});
loadMessages();
}
loadMessages();
</script>
</body>
</html>
将后端静态文件服务开启,即可拥有一个完全由 Notion 数据库驱动的留言板。
7. 生产环境注意事项与优化
7.1 速率限制与分页
Notion API 有频率限制(通常每秒 3 次请求),生产环境需增加重试逻辑,并对大批量查询使用 start_cursor 分页:
const response = await notion.databases.query({
database_id: databaseId,
page_size: 100,
start_cursor: nextCursor
});
7.2 错误处理
API 可能返回权限错误(404)、格式错误(400)等。务必 try...catch 并解析错误类型:
try {
await notion.pages.create(...)
} catch (error) {
if (error.code === 'object_not_found') {
console.log('数据库未授权或不存在');
}
}
7.3 安全与只读发布
- 切勿在前端直接调用 API,密钥必须保存在后端。
- 若只需展示数据,可开启 Notion 页面的“发布”功能,获取公开链接,结合 unofficial API 解析,但官方 API 是更推荐的安全方式。
8. 扩展思路:从留言板到真正应用
- 博客系统:用“状态”控制发布/草稿,内容用富文本,实现简单的 CMS。
- 用户反馈收集:表单提交 -> Notion API -> 数据库,团队成员直接在 Notion 协作处理。
- 自动化工作流:结合 Zapier、Make 等,监听数据库变化,触发邮件、通知等。
Notion API 让“文档即数据库”成为现实,极大降低了早期项目的开发复杂度。掌握本教程的增删改查、属性处理与工程化实践后,你完全可以尝试将 Notion 作为轻量后端,快速落地你的下一个创意。