ブログの改造をしてたらいつの間にかNotion APIの虜になってた

こちらはNotion Advent Calendar 2022の17日目です。  

https://qiita.com/advent-calendar/2022/notion

こんにちはhoromi([@mineral_30](https://twitter.com/mineral_30))です。  

私はNotion APIが大好きです。  
でもNotionも好きです。  

なぜNotion APIが好きになったかというと  
easy-notion-blogがキッカケでした。  
![Screenshot 2022-12-14 at 18.54.34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2742984/5c386f5d-a4f4-b436-793b-16599cb225b1.png)
https://github.com/otoyo/easy-notion-blog


今ではeasy-notion-blogのコミュニティ運営をしたり  
ちょっとしたPRを本家に送ってニヤニヤしたり  
ドハマリ中なhoromiではありますが  

はじめから  
こんな改造オタクではありませんでした。  

この記事では  
それまでに至ったNotion遍歴を紹介させていただこうと思います。



私のNotionはまず交換日記から始まりました。

# 気の合う仲間と交換日記

本当に気の合う仲間のみで始めたteamプラン(現 プラスプラン)。  

コメント機能をとことん使い続ける...  
といった運用の仕方でしたが  
招待制SNSのような感覚で楽しめました。  


プログラミングを趣味で始めたメンバーで  
構成されていて  

いつも  
「今何の勉強してるの？」というコメントから  
話題が発展していきます。  

全員が全く同じ課題に取り組むことは稀で  
大抵がバラバラ。  

でも興味はある。  

だから気になる。  

そんな感じで  
Twitterやネットなどで見つけた話題や  
オススメの本なども紹介し合ったりと  
交流を続けてかれこれ１年１０ヶ月。  

特にルールもなく  
気になった人がDBに収納したり  
ブロック制限に近づいてきたら  
専用アカウントに移動させたり  
なんとなくゆるく運用しています。  

![Screenshot 2022-12-14 at 15.43.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2742984/2ebe2952-1d59-ed17-e3ed-90a77a357135.png)



勉強したことをNotionに書き溜める習慣がついてきた時期に  
「ブログにして公開したい」  
という欲が出てきました。  


# ヘッドレスCMS_easy-notion-blog

Notionに書き溜めたのに  
わざわざ編集画面を開いて作業をするのは面倒です。  

ブログを続けられたためしがなかったので    
極力手間の少ないやり方でできるやり方は無いかと探しました。  


そんな時  
発見したのがeasy-notion-blogでした。  




https://alpacat.com/blog/easy-notion-blog


NotionDBに収納して  
それを記事として公開できる！！  


デザインも  
自由に改造できて  
 無料＼(^o^)／  
 
 ![Screenshot 2022-12-14 at 16.05.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2742984/0c67a844-2f56-2fbf-c981-a263d8083383.png)

 
 
 改造したくなるデザインというのがまた憎いッwww  
 
 
 結果的に改造に改造を重ねてこうなりました。
![Screenshot 2022-12-14 at 16.08.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2742984/8d640da1-9ca4-5258-6366-c2a12628580b.png)

 
 
 「これ作りたい！！」  
 
 という欲求のままに  
 コードを解読して  
 分からない部分は勉強して  
 作ってみて  
 失敗して  
 エラーに泣かされ  
 気づけばあっという間の１年でした。
 
 
 Notionのデータを使って  
 ブログに表示させているので  
 改造していく中で  
 Notion APIについても分かるようになってきたので  
 
 
 代表的なNotion APIメソッドをいくつか紹介します。
 
 ## NotionDB内Pageを取得する_Query a database
![Screenshot 2022-12-14 at 16.20.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2742984/a4df6245-06f2-718d-57ab-71464a0d6958.png)
https://github.com/otoyo/easy-notion-blog/blob/main/lib/notion/client.ts#L69


  
 これは  
 NotionDBに入れられたPageを全て取得するための関数です。  
 
Notionからは以下のような状態になっています。
![Screenshot 2022-12-14 at 16.23.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2742984/0366740b-df39-3ec5-b5f5-e52feab62952.png)

 
 公式リファレンスでは以下のように明記されています。
![Screenshot 2022-12-14 at 16.26.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2742984/17e657cb-6b14-d6c8-dbf8-4195a2b4ed64.png)
https://developers.notion.com/reference/post-database-query
 
 ``` Javascript
 const { Client } = require('@notionhq/client');

const notion = new Client({ auth: process.env.NOTION_API_KEY });

(async () => {
  const databaseId = 'd9824bdc-8445-4327-be8b-5b47500af6ce';
  const response = await notion.databases.query({
    database_id: databaseId,
    filter: {
      or: [
        {
          property: 'In stock',
          checkbox: {
            equals: true,
          },
        },
        {
          property: 'Cost of next trip',
          number: {
            greater_than_or_equal_to: 2,
          },
        },
      ],
    },
    sorts: [
      {
        property: 'Last ordered',
        direction: 'ascending',
      },
    ],
  });
  console.log(response);
})();
 ```
 
 このコードを使って実装するには  
 キャッシュの知識が必要だということに気づくことができました。  

https://alpacat.com/blog/cache-strategy-of-easy-notion-blog

 
 また  
 変数で整理していく様子も見て学ぶことができるので  
 自分で改造する時に  
 「分かりやすく書いていこう！」という意識で取り組めました。  
 
 
 queryメソッドは`lib/notion/client.tsx` で沢山使われているので  
 ブログには無くてはならない存在なんだなということも知れました。
 
 ## Page内のBlockを１つ取得する_Retrieve a block
 
![Screenshot 2022-12-14 at 16.39.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2742984/ca02481a-cffe-727c-1e96-8882e593c2e6.png)
https://github.com/otoyo/easy-notion-blog/blob/main/lib/notion/client.ts#L416
 
 
NotionのPageが記事の内容になるんですが、  
その中には様々なBlockが含まれています。  

それをswitchで条件反射させて取得していく様子を見ることができます。  

公式リファレンスでは以下のように明記されています。
![Screenshot 2022-12-14 at 16.44.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2742984/889f064e-0fbc-88df-d341-7b19a6f611b8.png)
https://developers.notion.com/reference/retrieve-a-block

``` Javascript
const { Client } = require('@notionhq/client');

const notion = new Client({ auth: process.env.NOTION_API_KEY });

(async () => {
  const blockId = 'c02fc1d3-db8b-45c5-a222-27595b15aea7';
  const response = await notion.blocks.retrieve({
    block_id: blockId,
  });
  console.log(response);
})();
```





Block内で入れ子にする場合にはもっと複雑になります。


## Block内の入れ子も含めて取得する_Retrieve block children

![Screenshot 2022-12-14 at 17.26.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2742984/d1fc5afd-09ed-cc94-5b25-81bd70e73842.png)
https://github.com/otoyo/easy-notion-blog/blob/main/lib/notion/client.ts#L372

Notionを使っていると  
当たり前のようにこんなことしませんか？


![Screenshot 2022-12-14 at 17.33.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2742984/49612989-45ea-729b-0ba1-37c26badece1.png)
![Screenshot 2022-12-14 at 17.34.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2742984/f54c1e7c-a024-8023-dd37-520368ff23ab.png)


Blockの中にまたblockをいれちゃうあれです。  
これをブログで実装すると  
びっくりするほど  
大変なんだなということが分かります。

![Screenshot 2022-12-14 at 17.37.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2742984/3cca4b82-e5cb-de77-577e-99aee549c090.png)
https://github.com/otoyo/easy-notion-blog/blob/main/lib/notion/client.ts#L372


Childrenっていうのがキーワードっぽいです。  


公式リファレンスではこう明記されています。
![Screenshot 2022-12-14 at 17.40.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2742984/ecbc5564-ae53-6fe3-86cc-c78edd786c78.png)
https://developers.notion.com/reference/get-block-children

``` Javascript
const { Client } = require('@notionhq/client');

const notion = new Client({ auth: process.env.NOTION_API_KEY });

(async () => {
  const blockId = '59833787-2cf9-4fdf-8782-e53db20768a5';
  const response = await notion.blocks.children.list({
    block_id: blockId,
    page_size: 50,
  });
  console.log(response);
})();

```


## NotionDBのPropertyにデータを追加する _Update page

easy-notion-blogは開発者([otoyoさん](https://github.com/otoyo))のブログの[コード](https://github.com/otoyo/notion-blog)も公開されています。

ここからたくさんのヒントを得ることができます。  

特に印象的だったのが【いいねボタン】のコードです。
![Screenshot 2022-12-14 at 17.50.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2742984/8f20cce3-e624-4dba-db71-5ec72a232d24.png)
https://github.com/otoyo/notion-blog/blob/main/src/lib/notion/client.ts#L687



これは  
記事末尾に設置されたいいねボタンをトリガーとして  
NotionDBのPropertyに＋1増やすという機能です。  


日常的によく使っているいいねボタンですが  
実装には頭を抱えるほど難しいということを知りました。  

> いいねボタンを押したときに直接呼び出せば良いような気がしますが、これはできません。
> JavaScript がアクセスできるのは、その JavaScript が生成されたドメインと同じドメインだけという決まりがあります。


https://alpacat.com/blog/update-notion-db-by-like-button

ブログの画面上でボタンが押されたら  
それをトリガーに  
apiでPUT通信をし  
Notionサーバーに送る。  
送れた合図で＋１をNotionDBのPropertyに入れる。  

といった流れです。

実際に私もブログに追加して体験してみました。  
![Screenshot 2022-12-14 at 18.05.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2742984/e552cbc8-e048-72bf-3cc8-03d7d1a8a57c.png)


▼NotionDB
![Screenshot 2022-12-14 at 18.06.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2742984/8c753457-2e83-cd2c-5a1e-c45445d07da2.png)



この改造で  
「ブログはNotionにある内容を公開するだけではなく、  
ブログからアクションしてもらってNotionにためることもできるんだな」  
ということを知りました。  

解説記事を読みながら  
習得できたことを  
まとめたのが以下の記事です。  

https://herohoro.com/blog/blog-learn_differ-server


公式リファレンスでは以下のように明記されています。
![Screenshot 2022-12-14 at 18.25.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2742984/9ae02c28-f550-5328-212e-3560508de82d.png)
https://developers.notion.com/reference/patch-page

``` Javascript
const { Client } = require('@notionhq/client');

const notion = new Client({ auth: process.env.NOTION_API_KEY });

(async () => {
  const pageId = '59833787-2cf9-4fdf-8782-e53db20768a5';
  const response = await notion.pages.update({
    page_id: pageId,
    properties: {
      'In stock': {
        checkbox: true,
      },
    },
  });
  console.log(response);
})();

```


## NotionDB内にPageを新規作成する_Create a page

![Screenshot 2022-12-14 at 18.14.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2742984/72082690-7621-3f42-c5c3-e95d1942a7fa.png)
https://github.com/herohoro/data-world-blog/blob/main/lib/submit_form/client.ts

これはいいねボタンからヒントを得て  
自分で実装したコードです。

ブログの画面上で入力フォームを用意し  
![Screenshot 2022-12-14 at 19.26.17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2742984/00928e61-32d4-0e58-2936-9ffcd41f9a68.png)
https://data.herohoro.com/world/submit

そこに入力されたデータを  
apiでPOST通信し  
Notionサーバーへ送る。  
そのデータをNotionDB内の１つのPageとして作成する...
![Screenshot 2022-12-14 at 19.32.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2742984/1f8d7315-717c-fe8e-76aa-63cc7a5b4205.png)


といった機能です。

特にapiの部分に苦戦しましたがなんとか完走しました。

https://herohoro.com/blog/post-inputform


ここまで来ると  
公式リフェレンスでは結構簡単に書かれてることでも  
実際にやろうとすると苦戦するなといったことを経験できました。
![Screenshot 2022-12-14 at 18.26.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2742984/56443d9f-a3d0-ceb1-5a5b-93933e231a95.png)
https://developers.notion.com/reference/post-page

``` Javascript
const { Client } = require('@notionhq/client');

const notion = new Client({ auth: process.env.NOTION_API_KEY });

(async () => {
  const response = await notion.pages.create({
    "cover": {
        "type": "external",
        "external": {
            "url": "https://upload.wikimedia.org/wikipedia/commons/6/62/Tuscankale.jpg"
        }
    },
    "icon": {
        "type": "emoji",
        "emoji": "🥬"
    },
    "parent": {
        "type": "database_id",
        "database_id": "d9824bdc-8445-4327-be8b-5b47500af6ce"
    },
    "properties": {
        "Name": {
            "title": [
                {
                    "text": {
                        "content": "Tuscan kale"
                    }
                }
            ]
        },
        "Description": {
            "rich_text": [
                {
                    "text": {
                        "content": "A dark green leafy vegetable"
                    }
                }
            ]
        },
        "Food group": {
            "select": {
                "name": "🥬 Vegetable"
            }
        }
    },
    "children": [
        {
            "object": "block",
            "heading_2": {
                "rich_text": [
                    {
                        "text": {
                            "content": "Lacinato kale"
                        }
                    }
                ]
            }
        },
        {
            "object": "block",
            "paragraph": {
                "rich_text": [
                    {
                        "text": {
                            "content": "Lacinato kale is a variety of kale with a long tradition in Italian cuisine, especially that of Tuscany. It is also known as Tuscan kale, Italian kale, dinosaur kale, kale, flat back kale, palm tree kale, or black Tuscan palm.",
                            "link": {
                                "url": "https://en.wikipedia.org/wiki/Lacinato_kale"
                            }
                        },
                        "href": "https://en.wikipedia.org/wiki/Lacinato_kale"
                    }
                ],
                "color": "default"
            }
        }
    ]
});
  console.log(response);
})();

```




# Twitterで広がったeasy-notion-blogの輪

easy-notion-blogにはコミュニティも用意されています。
![Screenshot 2022-12-14 at 18.30.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2742984/7fd47ec1-a7ba-a9a5-c1b9-07217c63eed2.png)
[easy-notion-blog/README/community](https://github.com/otoyo/easy-notion-blog#bird-twitter-community)

ツイートに`#easy_notion_blog`をつけると  
比較的関連した方々からイイネがあります。  

私が開発者のotoyoさん([@otoyo0122](https://twitter.com/otoyo0122))とつながれたのもTwitterのおかげでした。

導入で詰まってる方を見かけると  
私はすかさず飛んでいくようにしています。  

なぜなら  
ほぼ初心者状態でGitHubも分からなかった時期に  
easy-notion-blogを使い始めてしまい  
かなり苦労した経験があるからです。  

pushとかaddとか全然分かりませんでした。  


このコミュニティを通じて  
お互いのブログの情報交換をしています。  

「どんな改造したの？」  
「それ記事に出す予定ある？」  

など平和なやりとりもあれば  

「今回のアップデート大変〜〜〜」  
「ここで詰まってる」  

といった嘆きツイートもあり楽しいです。

でもみんなNotionが好きで  
好きだからずっと使いたくって  
ブログにして記事を出しているのかなと  
思ったりしています。  

# おわりに

Notionを使い始めてから
使えば使うほど欲が出てきて  
ブログを始め、  
easy-notion-blogがキッカケで
Notion API に触れるようになり  
ワクワクが止まらない１年でした。  

そんなeasy-notion-blogも  
Starがそろそろ３ケタになろうとしていて  

https://github.com/otoyo/easy-notion-blog


一緒にブログの改造をしながら  
Notion APIやNext.jsなどを  
習得できたらいいなと思っています＼(^o^)／


長くなりましたが  
最後まで読んでくださり  
ありがとうございました★