#11 No-code 之旅 — 在 Next.js 专案中显示 Notion 的资料 ft. Notion SDK

哈罗!昨天使用 SWR 实作了一个小功能,让使用者可以列出某 Github user 的所有公开 repository~ 今天用 Notion SDK 新增了一个新的页面,显示我的 Notion page 里面的内容,可以在这里看看喔。

Notion SDK

Getting Started

想要可以用 Notion SDK 或呼叫 Notion API 之前,我们要去做这些步骤取得权限:

  1. 新增一个 integration
    • My Integrations
    • 按 "+ New Integration" 按钮去
    • 输入需要的资料,例如 integration 名称,选 workspace
    • 按 "Submit" 送出,新增完了!
    • 现在把 "Internal Integration Token" 里的 secret 复制下来,放在安全的地方,我们之後会用到~
  2. 把 page 分享给 integration
    • 到你想要取得资料的 Notion page,像我的是这一页
    • 按 "Share" 打开分享小视窗
    • 点输入匡,会有新的小视窗出来
    • 里面应该会看到你刚新增的 integration
    • 选该 integration 然後按 "Invite"
  3. 复制你的 Notion page ID,像我的 URL 长这样 https://jadejs.notion.site/iTHome-0f3a86530c5e44d18004c5c689044c5d- 後面的一串字串是我们想要的 ID
  4. 把 secret token 和 page ID 写在 .env 档里面
    NOTION_TOKEN=secret_**********************************
    NOTION_PAGE_ID=0f3a86530c5e44d18004c5c689044c5d
    
    page ID 其实是公开的资讯,所以不一定要放在 .env 里~

Setup

我们现在要安装 Notion SDK,如果你们想要用 Notion API 也可以喔!不过我在这专案里使用的是 SDK:

npm install @notionhq/client
# or
yarn add @notionhq/client

装完之後我们可以开始用 SDK 了~

import { Client } from "@notionhq/client";

// 初始化 Client
const notion = new Client({
  auth: process.env.NOTION_TOKEN, // 刚刚把 secret token 写在 .env 里面的那个!
});

取得 Page 资料

豪!可以开始拿资料了~ Notion API 有提供很多 endpoints,例如我们今天要用的 pages.retrieve,就是取得该 page 的内容。

export const getPage = async () => {
  const pageId = process.env.NOTION_PAGE_ID; // 我们的 page ID
  const response = await notion.pages.retrieve({ page_id: pageId });

  // response 会是 page object
  return response;
};

response 为 JSON 格式的 page object:

{
  "object": "page",
  "id": "b55c9c91-384d-452b-81db-d1ef79372b75",
  "created_time": "2020-03-17T19:10:04.968Z",
  "last_edited_time": "2020-03-17T21:49:37.913Z",
  "parent": {
    "type": "database_id",
    "database_id": "48f8fee9-cd79-4180-bc2f-ec0398253067"
  },
  "archived": false,
  "url": "https://www.notion.so/Avocado-b55c9c91384d452b81dbd1ef79372b75",
  "icon": { "type": "emoji", "emoji": "?" },
  "cover": {
    "type": "external",
    "external": {
    	"url": "https://website.domain/images/image.png"
    }
  },
  "properties": {...}
}

使用 pages.retrieve 并不会拿到该 page 的 blocks (page 的内容),只会拿到 page 的一些资讯和 properties
Working with page content

图片来源:Working with page content

所以我们拿不到上面图中的连结和文字,可是我们会拿到 titleActor,还有封面图,新增编辑时间等。

取得 Blocks

export const getBlocks = async () => {
  // page 也是一种 block
  const blockId = process.env.NOTION_PAGE_ID;
  // 我们想拿到 page 里的 blocks,这里 block_id 等於 page ID
  const response = await notion.blocks.children.list({ block_id: blockId });

  // response 为 list of blocks
  return response;
};

以上面的图为例子,我们会拿到三个 blocks,第一个是连结,第二个是 Synopsis,第三个是 paragraph。

Notion 页

如果以上面的图为例子,就是我今天做的页面,我们大概会拿到像这样的 response

{
  "object": "list",
  "results": [
    {
      "object": "block",
      "id": "c164f4b2-ad9e-45df-859c-bbb5759eff00",
      "created_time": "2021-09-26T08:42:00.000Z",
      "last_edited_time": "2021-09-26T08:42:00.000Z",
      "has_children": false,
      "archived": false,
      "type": "heading_1",
      "heading_1": {
        "text": [
          {
            "type": "text",
            "text": { "content": "2021 铁人赛 | iT邦帮忙", "link": null },
            "annotations": {
              "bold": false,
              "italic": false,
              "strikethrough": false,
              "underline": false,
              "code": false,
              "color": "default"
            },
            "plain_text": "2021 铁人赛 | iT邦帮忙",
            "href": null
          }
        ]
      }
    },
    {
      "object": "block",
      "id": "0f707dff-1498-4416-a156-7c6ef2a026d1",
      "created_time": "2021-09-26T08:42:00.000Z",
      "last_edited_time": "2021-09-26T08:42:00.000Z",
      "has_children": false,
      "archived": false,
      "type": "heading_3",
      "heading_3": {
        "text": [
          {
            "type": "text",
            "text": {
              "content": "制作你的无程序码(No-code)个人网页 ft. Next.js, SWR, 串 Youtube, IG, Github, Notion API ~",
              "link": null
            },
            "annotations": {
              "bold": false,
              "italic": false,
              "strikethrough": false,
              "underline": false,
              "code": false,
              "color": "default"
            },
            "plain_text": "制作你的无程序码(No-code)个人网页 ft. Next.js, SWR, 串 Youtube, IG, Github, Notion API ~",
            "href": null
          }
        ]
      }
    },
    ...
  ],
}

每个 block 会有 idtype,新增编辑时间等,也包含该 block 的内容,像 heading_3 的 block,里面包含了 text 的阵列,每一个 text object 会有自己的格式 (formatting),写在 annotations 里面。我们可以根据 annotations 还有 href 的资讯决定该怎麽显示这个 text object (物件)~

用 Data Fetching 方式抓取资料

今天使用了 getStaticProps 抓取资料,可是也可以用 getServerSideProps,而且用 SSR 的话,页面可以拿到最新的内容!不过我这页面内容应该不会变,所以决定这麽写:

// pages/notion.js
export async function getStaticProps() {
  // 可以直接把 getPage 和 getBlocks import 进来~
  const page = await getPage();
  const blocks = await getBlocks();
  const data = { ...page, blocks };

  return {
    props: { data },
  };
}

小结

今天看了 Notion API 的文件,发现抓完资料还要做多处理!不过这也让我们有更多的弹性,想怎麽显示我们拿到的资料都可以~ 所以我从一开始打算把 Notion 当成 CMS 或是资料库,把资料都写在 Notion 里,然後再用 API 取这些资料去显示。今天的小功能有让我觉得好像离目标更近一步了!XD
大家可以看看在这里,然後 Notion 的 page 在这里

祝大家周末愉快!

Live Demo

晚安 <3

看更多


<<:  [Day 21] Leetcode 560. Subarray Sum Equals K (C++)

>>:  PHP 扩展库(extension) 和 套件(package)

开发环境与部署环境不同时的解决方案

我的开发环境是ubuntu20,但是部署环境是ubuntu18; 开发的语言是python,出现了一...

DAY 27 - 野猪枪手 (3) 完

大家好~ 我是五岁~ 今天来把野猪枪手完成吧~!! (๑•ૅω•´๑) 首先是上色~ 野猪就是咖啡色...

资料呈现与运算处理

前言 前端需负责画面上呈现的所有东西,可能是显示静态资料或是需要将原始资料经过繁复的运算得到结果,不...

索引合并(index merge)

一般来说,Mysql只会为单一索引生成扫描区间,但还是有特殊情况会为多个索引生成扫描区间。 这种为多...

<Day22>用Shioaji API模拟帐户做台股下单

● 这章会示范如何用Shioaji做台股下单 终於来到下单的环节啦~~~ 没有下单过,别说你进入过股...