Notion バックアップの実際の中身

バックアップとは、バックアップのために設計されていない API へ、何度もリクエストを送る作業です。この API が何を返し、何を返さないのかを正確に知ってはじめて、信頼できるコピーが手に入ります。

まず token から始まります

Notion はインテグレーションで、誰が何を読めるかを決めます。社内向けのインテグレーションを作ると、それは共有したページとデータベースだけを読めます。ワークスペースのほかの内容は読めません。共有しなければ、何も読めません。そのインテグレーションを識別するのが token です。

これが NotionManager の使うアクセスモデルのすべてです。Notion のパスワードは使いません。すべてを読めるワークスペース単位の鍵もありません。共有していないページも読めません。インテグレーションが何を読めるかは共有リストが決めます。Notion はほかのどのツールにも同じルールを適用します。Notion 側でインテグレーションを取り消せば、以降の実行はすべてすぐに失敗します。

次に API ができることを決めます

Notion API は block とページに向けた、ページ分割された読み取り用のインターフェースです。結果をページ単位で返し、1 ページは最大 100 件です。1 秒あたりに送れるリクエスト数も制限します。表現できるものは完全に返します。表現できないものは、内容を推測せずに block の種類だけを報告します。

ページ分割、呼び出し制限、返せない内容が、Notion のバックアップの設計を決めます。つまりバックアップは 1 回のリクエストではありません。一定のペースで進む走査です。大きなワークスペースでは、数分、十数分、あるいはそれ以上かかります。NotionManager は進捗をリアルタイムで表示するので、どこまで進んだかがいつでも分かります。

Notion は不具合の修正、新機能の追加、データ構成の改善のために API を更新し続けています。NotionManager は最新バージョンの API を使って作られているので、バックアップの完全性のためにできるだけ多くの情報を取得できます。

バックアップが複製するデータモデル

Notion のすべては block でできています。本文、見出し、ToDo、トグル、テーブルの 1 行、どれも block です。ページもまた block で、ほかの block を含んでいます。つまり Notion で読むものはすべて block の木です。バックアップも同じようにこの木を読みます。あるノードから始めて、子ノードを読み、それを繰り返します。

データベースはページの入れ物です。中身は 1 つ以上のデータソースにあり、データソースの各行が 1 つのページです。そのページのプロパティはデータソースが定義します。ビューはデータを自分では持ちません。データをどう見るかを定義します。どのデータソースを見るか、どのフィルターと並び順を使うか、テーブル、ボード、カレンダー、ギャラリーのどれで見せるかです。Notion API はビューの主要な構造を返し、スタイルは返しません。

NotionManager がワークスペースを読む手順

上から下への 1 回の走査です。API が結果を返さなくなるまで続きます。

  1. 1

    共有したものから始める

    integration token は、共有した最上位のページとデータベースを公開します。これが走査の起点です。

  2. 2

    それぞれを最後まで読む

    NotionManager は各起点をプロパティと block ごと取得し、ページ分割が終わるまで 1 ページずつ読みます。取りこぼしはありません。

  3. 3

    子ページをたどり続ける

    途中で見つけた子ページを順に再帰的に取得し、子ページがなくなるまで続けます。

  4. 4

    構造を再構築してから読む

    NotionManager は読み取った内容をページ、データベース、関係として再構築します。その結果は、JSON の山ではなく、Notion に近い感覚でオフラインで閲覧できる読み取り専用のコピーです。

API がしないこと、そして代わりに起きること

Notion API の制限NotionManager の対応
API はリクエスト数に制限があり、バックアップに時間がかかるNotionManager は一定のペースでリクエストを送り、制限に当たったら待つので、コピーは完全なままです。
block の種類によっては、API が中身を返さない読み取れる生の情報はすべて残します。描画時に不足を明示するので、穴は黙って空くのではなく目に見えます。
ビューの複雑なスタイルNotionManager はビューの背後にあるデータをコピーし、プロパティからビューを再構築します。Notion の動作をできるだけ再現します。
変更フィードがない:API は「この 3 ページが火曜日から変わった」と言えない現時点では有効な差分バックアップを提供できません。そのため毎回、すべてのページと block をたどります。ただし変わっていない block は余分なディスク容量を使いません。外部メディアファイルも重複を除いて保存するので、ディスク容量を有効に使えます。
書き戻しができない:API はワークスペースを復元できないバックアップからの復元は直接サポートしていません。復元をうたうバックアップはどれも完全な再構築で、id の変更や関係の喪失といった大きな制限があります。NotionManager は設計として復元操作に対応しません。
インテグレーションに共有していない内容何も含まれません。コピーに入るのは、共有したページだけです。NotionManager は共有したページの一部を選ぶなど、範囲をさらに絞れますが、この範囲を超えることはできません。

NotionManager でバックアップする

インテグレーションを作成し、ページかデータベースを共有して、最初のコピーが現れるのを見てください。

次に読む

よくある質問

NotionManager に Notion のパスワードは必要ですか?

いいえ。使うのは integration token で、そのインテグレーションは明示的に共有した内容だけを読めます。ワークスペース全体の資格情報は使いません。

なぜバックアップに数分、あるいはそれ以上かかるのですか?

1 つ目の理由は、Notion API の呼び出し速度の制限がとても厳しいことです。速めようとすると同時実行が増えて制限に当たります。2 つ目の理由は、毎回のバックアップが全件だからです。データを再取得する必要がない場合でも、コピーの完全性を確かめるには、すべてのページとすべての block をたどる必要があります。

変化した部分だけをバックアップできますか?

現在の Notion API では、前回のバックアップ以降の変更一覧を確実に取得できません。そのため毎回が全体バックアップになります。ただし NotionManager は、同じデータを 1 つだけ保存するように賢く処理します。

API が説明しない block はどうなりますか?

NotionManager は、その block が宣言している種類と木の中での位置を記録します。だからギャップは、ページの途中に黙って空いた穴ではなく、閲覧できるコピーの中で目に見えます。