NotionをDBにして「いつでもアドベントカレンダー」を作ってみた

アドベントカレンダーって、
期限が決まっていて、自分がやると宣言したのだから、切羽詰まって進捗出ますよね！
これを書き上げているのも公開日前夜！
このギリギリを責める感じ、自分の計画性のなさが露呈します。

「期限を決めて、宣言して自分を追い込む。」
計画性のない人間にとっては必要なことだと思うのです。


これが12月だけって、ちょっともったいない気がしませんか？
いつでもできるアドベントカレンダー、必要だと思いませんか？


せっかくなので、それをJamstack構成で作っちゃおうというのがこの記事です。

だいたい入力にはHeadlessCMSとかそういったものを使用すると思うのですが、今回は前から気になっていた[Notion](https://www.notion.so/)をCMS代わりに使ってみたいと思っています。

## 成果物
![advent_logo.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/48488/d5ca53de-8d1c-9517-dbb3-864ce24a7915.png)

少しでも楽しそうな感じになるように努力しました。
![スクリーンショット 2020-12-05 19.08.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/48488/eeea7a26-c31e-4cbf-1027-037e4782cb1b.png)


https://pocchi-adventcalendar-2020.netlify.app/202012
https://github.com/Pocchi/advent-calendar2020

ちなみに、かわいいお猿さんは[こちら](https://www.linustock.com/vectors/sports/surfing/awm00002)からお借りしました。


## Notionにデータベースを用意する
Default Viewとして、Tableを用意しました。
![スクリーンショット 2020-12-03 10.09.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/48488/e59047c4-7370-bdca-8ea3-5e630ddf68d9.png)
「全てを自分で書くんだ！」という強い気持ちを持たせるために、writer欄を用意して、自分を入れました。
ここで注意するのが、urlもTextで用意することです。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/48488/f445a54f-6e46-11e9-4962-ebc2c018786a.png" width="400">
URLもあるのですが、APIを通してデータを取得した時に、`Not Supported`の文字列が入ってきてしまいます。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/48488/8db29241-bb06-e935-43ff-56380327a080.png" width="450">



## Notionからデータを取得する
Notionをブログとして公開する、[notion-blog](https://github.com/ijjk/notion-blog)という素敵なものもありますが、
今回はDBとしてNotionを使用したいので、[こちらの記事](https://note.com/usaginoniku/n/n974aab7f67fa)を参考にしました。
現在、Notionの公式なAPIはないようで、非公式なものを使います。
使用したのは[notion-api-worker](https://github.com/splitbee/notion-api-worker)です。

参考記事を見て、
データを取得したいNotionのページのURLから`PAGE_ID`を、Cookie(token_v2)から`TOKEN`を拾ってきました。

```js
const { data } = await $axios.get(
      `https://notion-api.splitbee.io/v1/table/${process.env.PAGE_ID}`,
      {
        headers: { Authorization: `Bearer ${process.env.TOKEN}` },
      }
    )
```
これでデータを取得できました。
配列の中にオブジェクトで入ってきます。

```js
[
  {
    id: 'e937a6ac-1d98-48d8-8e03-e6486d3f2118',
    date: '2020-11-16',
    writer: '自分',
    url: 'https://www.google.com/',
    comment: '何か'
  },
  {
    id: '513c77a3-121a-4792-ab1f-294e760c11e1',
    date: '2020-12-11',
    writer: '自分',
    comment: '何か2'
  }...
]

```


## Nuxtでカレンダーを作る
Nuxtのverとモードはこちら。
`target: static`で使用しています。

```
   ╭───────────────────────────────────────╮
   │                                       │
   │   Nuxt.js @ v2.14.7                   │
   │                                       │
   │   ▸ Environment: development          │
   │   ▸ Rendering:   server-side          │
   │   ▸ Target:      static               │
   │                                       │
   │   Listening: http://localhost:3000/   │
   │                                       │
   ╰───────────────────────────────────────╯
```
できた画面としてはこんな感じ。
https://5fcb40ea07edeeb8b84e8a4a--pocchi-adventcalendar-2020.netlify.app/202012/
![スクリーンショット 2020-12-05 17.00.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/48488/519dbf32-8583-9277-208e-0ebeae8de0b2.png)


[vuetifyのカレンダー](https://v2.vuetifyjs.com/ja/components/calendars/)を使用しました。
通常であれば、`<前の月`や`次の月>`のように遷移するボタンを用意するのですが、今回はヘッダにデータのある月のリンクだけ用意しています。

### URLの指定
`localhost:3000/[YYYYMM]`
のようにURLに年月を渡して、その月のカレンダーを表示しています。

APIから取得して動的に生成するURLなので、nuxt.config.jsでgenerateを指定する必要があります。
(指定しないとページが生成されず、直アクセスで404になってしまいます。)
Nuxtのv2.13から
ページに貼ってあるリンクからクロールして勝手にページを生成してくれるようになったので、1つのページだけとりあえず指定しておけば問題ないです。([参考](https://ja.nuxtjs.org/docs/2.x/configuration-glossary/configuration-generate/#routes))

```nuxt.config.js
  generate: {
    routes() {
      return ['/202011']
    },
  },
```
これだけでリンクを貼っている3ページ分が静的に生成されました。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/48488/97991451-45da-eff7-2571-8713e73e091c.png" width="300">
余談ですが、リンクの値を間違って貼ってしまうと、generate時にエラーが起きてしまいますので気をつけましょう。(自戒。原因が分からず、調査してクロールに気づきました。数時間溶けた。)

## Netlifyでホスティングする
ローカルで環境変数をdirenvで使っていたのですが、Netlifyの方でも設定が必要です。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/48488/5bf2bc0d-2fe2-3de3-b737-842024dded8d.png" width="300">
(すっかり忘れていてページの生成時にAPIにアクセスできずに500になってしまいました。)
ちなみに、Nuxt.jsの困ったところなのですが、500でページの生成が失敗したとしても、正常終了してそのままデプロイしてしまいます。
![スクリーンショット 2020-12-05 17.36.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/48488/c264582e-4fb2-fcb7-5665-0b3d6b8dfd34.png)

オプションでエラー時にビルドを失敗させることができるので、`--fail-on-error`をつけておいた方が無難です。
![スクリーンショット 2020-12-05 17.39.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/48488/41fdcf1a-2fcd-e343-e257-7a4696f8c1dc.png)

あと、keyの隠蔽は忘れずにしておきましょう。
PAGE_IDとTOKENがあれば誰でもデータが取得できてしまいます。
[こちら](https://qiita.com/resistance_gowy/items/3cc57f90d8b480b529a5)の記事を参考に、production時は`privateRuntimeConfig`でビルド時のみkeyを参照できるようにしました。


## 今後のロードマップ(未定)
### webhook
ちゃんと運用していくためにはNotionを更新したらNetlify側でデプロイするようなwebhookの設定が必要です。
ちょっとだけ調べてみたのですが、Notion側からデプロイをアクションするための、ブラウザ拡張を自作するようなアプローチを見つけました。
https://github.com/dragonman225/trigger-webhook-from-notion

### POST
Notionを更新せず、DBとしてだけ使えないのか？と考えています。
GETだけでなく、POSTもしてみたい。
以下を読んでみたところ、できそうかな・・と思いましたが、とりあえず思っただけです。
https://github.com/jamalex/notion-py
https://tomohisaoda.com/posts/2020/notify-public-page-on-notion-to-slack.html