Notionを色々触っていたらターミナルからCRUD操作+αを実行したくなったのでCLIツールを作った

今年のお盆期間中は特にやることもなかったので、やりたくて時間が取れていなかったNotionのCLIツール作成をずっとやっていて、それがある程度は使えるレベルになったのでその紹介記事を書きました。

背景

Notion関連のツールはこれまでに以下作成してきましたが、ツールを作成する際に扱うNotion上のあるリソースのオブジェクト情報を知りたい時がたまにあり、その都度デバッグ用に標準出力するコードを書いたりしていました。また、Notionのデータベースに大量にあるページに対してあるプロパティの値を一括で更新したいというようなユースケースも発生するようになりました。このようにNotionを日々運用する中でWeb UIやAPIだけでは操作が容易でないユースケースを解決するためNotionに対しCRUD操作をインタラクティブに実行できるCLIを作ろうと思ったのがモチベーションです。

notion-cli

github.com

特徴としては各種フォーマットでの出力とインタラクティブ機能です。CLIフレームワークにはoclifを採用しており、サブコマンドの追加や各種フォーマットでの出力などなどCLIに必要な機能が全て揃っており、特に出力が主なフォーマットに対応しているので本来やりたいことに集中して実装することができました。

notion-cliの特徴

  • Notion上にあるページ、データベースなどに対するCRUD操作が可能
    • create/update系はリソースによってはプロパティの情報を渡す必要があるのでまだほぼ未サポート
  • 一部のコマンドはoclifのux.tableがサポートする出力形式に対応(table, csv, json, yaml)
  • 基本的にすべてのコマンドはNotion APIJSONレスポンスをそのまま出力
    • ux.tableをサポートしているコマンドは--rawをつける必要がある
  • 一部コマンド(db)にはインタラクティブ機能もありIDを渡さなくても対話的に操作を実行することも可能
    • Queryコマンドにはフィルター条件をJSONファイルとして保存して再利用することも可能

インストール

現在はnpmとdocker imageを提供しています

$ npm install -g @litencatt/notion-cli

$ docker pull ghcr.io/litencatt/notion-cli

使用方法

今回はとりあえずシュッと試してもらえるようにdockerでの使用方法を説明します。また、現時点ではux.tableをサポートしているコマンドで出力される項目はTitie, Object, Id, Urlだけにしているため、それ以外の情報も出力したい場合は後述する--rawフラグを付けて実行してください。

# 例: Testをタイトルに含むページの検索

$ cat .env
NOTION_TOKEN=secret_xxx...

# -e NOTION_TOKEN=secret_xxx...で渡しても可
# デフォルトはテーブル形式での出力
$ dk run --env-file=.env ghcr.io/litencatt/notion-cli:latest search -q Test
 Title            Object   Id                                   Url
 ──────────────── ──────── ──────────────────────────────────── ────────────────────────────────────────────────────────────
 test             page     b445c54a-1016-4abe-86e0-408e0b0781a2 https://www.notion.so/test-b445c54a10164abe86e0408e0b0781a2
 test2            page     1765f6c2-c191-48d9-b8fd-31c4295fa45f https://www.notion.so/test2-1765f6c2c19148d9b8fd31c4295fa45f
 test3            page     8272e55d-6a26-4aa2-a188-57819c3a586e https://www.notion.so/test3-8272e55d6a264aa2a18857819c3a586e
 Notion CLI Test1 database bcf4c9de-3003-4cfc-b8d2-e942a3643b1c https://www.notion.so/bcf4c9de30034cfcb8d2e942a3643b1c

# csv形式での出力をしたい場合は --output csvをつける
$ dk run --env-file=.env ghcr.io/litencatt/notion-cli:latest search -q Test --output csv
Title,Object,Id,Url
test,page,b445c54a-1016-4abe-86e0-408e0b0781a2,https://www.notion.so/test-b445c54a10164abe86e0408e0b0781a2
test2,page,1765f6c2-c191-48d9-b8fd-31c4295fa45f,https://www.notion.so/test2-1765f6c2c19148d9b8fd31c4295fa45f
test3,page,8272e55d-6a26-4aa2-a188-57819c3a586e,https://www.notion.so/test3-8272e55d6a264aa2a18857819c3a586e
Notion CLI Test1,database,bcf4c9de-3003-4cfc-b8d2-e942a3643b1c,https://www.notion.so/bcf4c9de30034cfcb8d2e942a3643b1c

# APIのレスポンスJSONをそのまま出力したい場合は --raw をつける
$ dk run --env-file=.env ghcr.io/litencatt/notion-cli:latest search -q Test --raw | jq . | head
{
  "object": "list",
  "results": [
    {
      "object": "page",
      "id": "b445c54a-1016-4abe-86e0-408e0b0781a2",
      "created_time": "2023-06-24T04:25:00.000Z",
      "last_edited_time": "2023-08-14T08:19:00.000Z",
      "created_by": {
        "object": "user",

インタラクティブ機能

現在はデータベースだけですが、対象リソースのIDが分からなくてもデータベース名から対象を選択してCRUD操作を実行できるようなインタラクティブ機能も実装しています。 そしてQueryコマンドにおいては対話的にフィルター条件を決定するとができ、かつその条件はJSONファイルとして保存することも可能です。そして保存した条件は次回実行時に指定して渡すことで同じ条件で繰り返しクエリを実行することも可能です。

image

ただしJSONファイルの保存はdockerでは現在対応していないためgifはnpm版の操作となっています

また、インタラクティブ機能を使用しなくてもIDと保存したフィルターのパスを指定すれば一発で情報を取得することができます

$ notion-cli db query DATABASE_ID -f ./path/to/filter.json

TODO

もともとのモチベーションとしてあった1つ目のユースケース(Notionのリソースに対するCRUD操作)は現時点でできるくらいの完成度にはなっていますが、もう一つのページプロパティの値の一括更新が残っています。イメージとしてはUPDATE foo SET bar = 1 WHERE status = "Done"のようなSQLを実行した場合に変更される処理を実装するイメージなのですが、プロンプトの実装をもう少し頑張ろうと思います。