NotionのデータベースビューテーブルにcURLからData APIで行を追加してみた

Notionのデータベースビューテーブルのレコードの追加は、親ページに子ページを追加して実現されています
2024.05.16

Notionのデータベースビューテーブルでは、レコードの追加は親ページ(データベース)に子ページ(レコード)を追加して実現されています。 呼び出すAPIは https://api.notion.com/v1/pages への POST リクエストであり、APIに利用するインテグレーションには「コンテンツを挿入」機能が必要です。

初手でインテグレーションの挿入権限不要、データベースの更新APIを検討して回り道してしまったので、知見を共有します。

RDBへのSQL操作でも、レコード追加はテーブルへの更新(ALTER)ではなく、テーブルへのレコード追加(INSERT)なので、このようなAPI操作は自然です。

なお、 Notionのテーブルはシンプルテーブルとデータベースビューテーブルの2種類があります。本記事のテーブルは後者です。

オブジェクトIDとデータベースとレコードの親子関係を確認

NotionのページやデータベースにはIDが割り振られています。

このIDは(共有)URLから確認できます。

例えば、ページのURLは次のような形をしています

https://www.notion.so/prefix-ランダムな32桁の英数字

この URL末尾の32桁の文字がページIDです。 具体的には、 1429989fe8ac4effbc8f57f56486db54 のような文字列であり、 1429989f-e8ac-4eff-bc8f-57f56486db54 というように 8-4-4-4-12 のブロックに分けることができます。

ページに含まれているテーブルそのものをページとしてオープンすると、同様に、URLに32桁の文字が含まれています。これがデータベースIDです。

同様に、テーブルの各行は新しいページとしてオープンでき、この行単体のビューのURLに含まれる32桁の文字が各行に割り当てられたページIDです。

Notionのデータベースにおいて、ページやデータベースやデータベース内の各レコードは独立したオブジェクトであり、IDが割り振られていることを確認したところで、以降では cURL からテーブルをAPI操作します。

cURLでNotionテーブルにレコード追加

1. API操作用インテグレーションを作成

次のURLの「私のインテグレーション」からAPI操作用のインテグレーションを作成します。

https://www.notion.so/my-integrations

secret_で始まるトークンを控え、環境変数に設定します。

$ export NOTION_API_KEY=secret_XXX

テーブルに行追加する場合、「機能(Capabilities)」メニューから「コンテンツを挿入(Insert content)」がチェックされていることを確認してください。

前述の通り、行の追加=ページの追加のため、新規作成権限が不足する場合、ページ作成時に以下の様な403エラーが発生します。

{
  "object": "error",
  "status": 403,
  "code": "restricted_resource",
  "message": "Insufficient permissions for this endpoint.",
  "request_id": "5dbaabbd-e70e-4b27-8dbe-f828bf152fdf"
}

2. 操作先ページとインテグレーションを接続

NotionでData APIを操作するには、操作対象のページとインテグレーションが接続されている必要があります。

親ページを接続すると、その子ページも操作可能になります。

この設定を忘れると、以下の様な404エラーが発生します。

{
  "object": "error",
  "status": 404,
  "code": "object_not_found",
  "message": "Could not find page with ID: YYY. Make sure the relevant pages and databases are shared with your integration.",
  "request_id": "7c8f83bf-b7ef-4174-88f4-715b082c632e"
}

3. cURLからページやデータベースを参照

Notion のData API利用時には、リクエストヘッダー(Authorization: Bearer NOTION_API_KEY)にトークンを渡します。

ページを参照

ページを参照するには、エンドポイント https://api.notion.com/v1/pages/ に対して、ページIDをURIパスに渡して GET リクエストします。

テーブル内の行に相当するページを参照します。 レスポンスから、親がデータベースであることもわかります。

$ export PAGE_ID=xxx
$ curl 'https://api.notion.com/v1/pages/'"$PAGE_ID" \
  -H 'Notion-Version: 2022-06-28' \
  -H 'Authorization: Bearer '"$NOTION_API_KEY"''

# レスポンス

{
  "object": "page",
  "id": "YOUR_PAGE_ID",
  ...
  "parent": {
    "type": "database_id",
    "database_id": "6fYYY-..."
  },
  ...
  "properties": {
    "作業日": {
      "id": "CsQO",
      "type": "date",
      "date": {
        "start": "2024-05-19",
        "end": null,
        "time_zone": null
      }
    },
    "数値": {
      "id": "Uc%3D%7C",
      "type": "number",
      "number": 4
    },
    "備考": {
      "id": "title",
      "type": "title",
      "title": [
        {
          "type": "text",
          "text": {
            "content": "aiueo",
            "link": null
          },
          ...
        }
      ]
    }
  },
  "url": "https://www.notion.so/aiueo-YOUR_PAGE_ID",
  "public_url": null,
  "request_id": "c1ee38eb-69a0-4ba4-82a8-99cf38bcb3b1"
}

インテグレーション接続した元ページ、すなわち、テーブルの親ページのIDを指定しても、同様に参照できます。

データベーステーブルを参照

データベースを参照するには、エンドポイント https://api.notion.com/v1/databases/ に対して、データベースのIDをURIパスに渡して GET リクエストします。

デーブルの実データではなく、スキーマ情報を取得できます。親がデータベースを埋め込んでいるページであることもわかります。

$ export DB_ID=YYY
$ curl 'https://api.notion.com/v1/databases/'"$DB_ID" \
  -H 'Authorization: Bearer '"$NOTION_API_KEY"'' \
  -H 'Notion-Version: 2022-06-28'

# レスポンス

{
  "object": "database",
  "id": "YYY",
  ...
  "title": [
    {
      "type": "text",
      "text": {
        "content": "テストテーブル",
        "link": null
      },
      ...
    }
  ],
  "description": [],
  "is_inline": true,
  "properties": {
    "作業日": {
      "id": "CsQO",
      "name": "作業日",
      "type": "date",
      "date": {}
    },
    "数値": {
      "id": "Uc%3D%7C",
      "name": "数値",
      "type": "number",
      "number": {
        "format": "number"
      }
    },
    "備考": {
      "id": "title",
      "name": "備考",
      "type": "title",
      "title": {}
    }
  },
  "parent": {
    "type": "page_id",
    "page_id": "ZZZ"
  },
  "url": "https://www.notion.so/YYY",
  ...
  "request_id": "4053eb9d-b52c-44a3-a745-f1c49b84c35f"
}

4. テーブルに行追加

最後が本題のテーブルへの行追加です。

前述の通り、行追加はデータベースの更新ではなく、親ページ(データベース)への子ページ作成で実現されています。

ページを作成するAPIのドキュメントの1行目を引用します。

Creates a new page that is a child of an existing page or database. https://developers.notion.com/reference/post-page

データベースの更新APIでは、このページ作成APIに誘導されています。

To add a new row to a database, use the Create a page endpoint. https://developers.notion.com/reference/update-a-database

親ページとなるデータベースIDを parent で指定し、追加するデータをカラム情報(プロパティ)とともにJSONで渡して POST リクエストします。

次の例では、よく使われる Date、 Number、Text のデータ型を用いています。

レスポンスから、データベースオブジェクトの親ページにページオブジェクトの子ページが追加されたことがわかります。

$ export DB_ID=YYY
$ 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": {
    "database_id": "'$DB_ID'"
  },
  "properties": {
    "作業日": {
      "date": {
        "start": "2024-05-20"
      }
    },
    "数値": {
      "number": 4
    },
    "備考": {
      "title": [
        {
          "text": {
            "content": "あいうえお"
          }
        }
      ]
    }
  }
}'


# レスポンス

{
  "object": "page",
  "id": "WWW",
  ...
  "parent": {
    "type": "database_id",
    "database_id": "YYY"
  },
  ...
  "properties": {
    "作業日": {
      "id": "CsQO",
      "type": "date",
      "date": {
        "start": "2024-05-20",
        "end": null,
        "time_zone": null
      }
    },
  ...
}

親ページのデータベースを GET すると、スキーマ情報を得られるため、型ごとの記述方法も確認できます。

抜粋

    "数値": {
      "id": "Uc%3D%7C",
      "name": "数値",
      "type": "number",
      "number": {
        "format": "number"
      }
    },

参考