😎
NextJS(AppRouter)で叩くNotion Api
目的
ホームページを作成する際に、ページの更新をしていくのは開発者だけでなく、一般の人(コードが書けない人)も更新ができるようになれば、開発側の負担軽減、ページの即時更新につながる。。そのため誰でも編集が可能である notion を利用することにした。
実際のコード
使用技術
- notionhq/client(2.2.14)
- next(14.0.4)
- react(18),
- notion-to-md (3.1.1),
- react-markdown (9.0.1)
- remark-gfm(4.0.0)
事前準備
notion の事前準備
integrations の設定
https://www.notion.so/my-integrations にアクセスをし、インテグレーションの作成を行う
インテグレーションの作成を行うとシークレットキーが得られる。またこのシークレットキーは api を叩く際に必要なためメモをしとくこと。
データベースの作成と設定
- notion でデータベースを作成
- 右上の 3 点リーダを選択
- 接続先を選択
- intergations で設定したプロジェクト名を選択
データベースの作成と設定
作成したデータベースの url(xxx の部分)をメモをする。
https://www.notion.so/xxxxx?v=yyyyy
NextJs の事前準備
NextJs のフレームワークをインストール
npx create-next-app@latest --typescrip
パッケージをインストール
@notionhq/clint は、Notion データベースのクエリを実行してデータを取得するパッケージである。
notion-to-md は,Notion の本文を取得し、MarkDown 書式で生成してくれるパッケージである。
イメージとしては、Notion のテーブル、メタデータを取得したければ、@notionhq/clint を利用し、本文を取得したければ、notion-to-md を利用する感じである。
npm i @notionhq/client notion-to-md
.env ファイルに記述
.env ファイルをプロジェクト直下に記述。notion で取得したシークレットきーと url(xxxx の部分)をそれぞれ env ファイルに記載する。
NEXT_PUBLIC_NOTION_API_KEY = "secret_aaaaaaa"
NEXT_PUBLIC_DB_URL = "xxxx"
NotionClient を作成
import { Client } from "@notionhq/client";
// Notion APIのクライアントを作成
export const notion = new Client({
auth: process.env.NEXT_PUBLIC_NOTION_API_KEY,
});
フロントのコードの作成
import React from "react";
import { headers } from "next/headers";
const page = async () => {
const host = headers().get("host");
// テーブルデータの取得
const responseTableData = await fetch(`http://${host}/api/notion`);
const tableData = await responseTableData.json();
// ページデータの取得
const detailId = "aifhaifhaie;hfaiehfae;hfae"; //ページID(テーブルを取得する際にメタデータとしてidが得られる
const responsePageData = await fetch(`http://${host}/api/notion/${detailId}`);
const Data = await responsePageData.json();
return <div></div>;
};
export default page;
実際のコード
メタデータ、テーブルデータの取得
import { notion } from "@/utils/notionClient";
import { NextResponse } from "next/server";
const corsHeaders = {
"Access-Control-Allow-Origin": "*", // すべてのオリジンからのアクセスを許可
"Access-Control-Allow-Methods": "GET", // 許可されるHTTPメソッド
"Access-Control-Allow-Headers": "Content-Type", // 許可されるヘッダー
"Content-Type": "application/json",
};
export async function GET() {
try {
const databaseId = process.env.NEXT_PUBLIC_DB_URL || "DEFAULT_DATABASE_ID";
const notionResponse = await notion.databases.query({
database_id: databaseId,
});
//実際にフロントに返すデータを決める。
const Response = await Promise.all(
notionResponse.results.map(async (result: any) => {
const id = result.id; // eslint-disable-line
const title = result.properties.name.title[0].plain_text; // eslint-disable-line
return { id, title };
})
);
return new NextResponse(JSON.stringify(Response), {
headers: corsHeaders,
status: 200,
});
} catch (error) {
console.error(error); // エラーをコンソールに出力
return new NextResponse(
JSON.stringify({ error: "Internal Server Error" }),
{
headers: corsHeaders,
status: 500,
}
);
}
}
notionResponse の中身としては、以下の写真の通りとなる。テーブルの中身だけでなく、そのテーブルの作成日、更新日、更新者などメタデータも取得ができる。実際にテーブルデータは、properties に入っている。
{
object: 'list',
results: [
{
object: 'page',
id: 'xxxxxx',
created_time: '2024-02-25T01:24:00.000Z',
last_edited_time: '2024-02-25T14:52:00.000Z',
created_by: [Object],
last_edited_by: [Object],
cover: null,
icon: null,
parent: [Object],
archived: false,
properties: [Object],
url: 'https://www.notion.so/yyyyy',
public_url: null
},
{
object: 'page',
id: 'xxxx',
created_time: '2024-02-25T01:24:00.000Z',
last_edited_time: '2024-02-29T06:38:00.000Z',
created_by: [Object],
last_edited_by: [Object],
cover: [Object],
icon: [Object],
parent: [Object],
archived: false,
properties: [Object],
url: 'https://www.notion.so/yyyy',
public_url: null
}
],
next_cursor: null,
has_more: false,
type: 'page_or_database',
page_or_database: {},
request_id: 'zzzzzzzzz'
}
ページデータの取得
import { NotionToMarkdown } from "notion-to-md";
import { NextResponse } from "next/server";
import { notion } from "@/utils/notionClient";
const corsHeaders = {
"Access-Control-Allow-Origin": "*", // すべてのオリジンからのアクセスを許可
"Access-Control-Allow-Methods": "POST, GET, OPTIONS, DELETE, PUT", // 許可されるHTTPメソッド
"Access-Control-Allow-Headers": "Content-Type", // 許可されるヘッダー
"Content-Type": "application/json",
};
export async function GET(
request: Request,
{ params }: { params: { id: string } }
) {
try {
const { id } = params;
const n2m = new NotionToMarkdown({ notionClient: notion });
const mdblocks = await n2m.pageToMarkdown(id);
const mdString = n2m.toMarkdownString(mdblocks);
const response = mdString.parent;
return new NextResponse(JSON.stringify(response), {
headers: corsHeaders,
status: 200,
});
} catch (error) {
console.error(error); // エラーをコンソールに出力
return new NextResponse(
JSON.stringify({ error: "Internal Server Error" }),
{
headers: corsHeaders,
status: 500,
}
);
}
}
実際にデータをフロントエンドに返す際は、Markdown 形式で返している。
補足
- 関連サービスの紹介
- react-markdown (9.0.1) (Markdown を HTML に変換するパッケージ)
- remark-gfm(4.0.0) (Markdwon に css を適応できるようにするパッケージ)
- 参考文献や、公式ページへのリンクなど
https://github.com/nagisa599/notion-api-study
おわりに
notion データベース意外と何でもできる~ 便利~
Discussion