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


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

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

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

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

だいたい入力にはHeadlessCMSとかそういったものを使用すると思うのですが、今回は前から気になっていたNotionをCMS代わりに使ってみたいと思っています。

成果物

少しでも楽しそうな感じになるように努力しました。

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

ちなみに、かわいいお猿さんはこちらからお借りしました。

Notionにデータベースを用意する

Default Viewとして、Tableを用意しました。

「全てを自分で書くんだ!」という強い気持ちを持たせるために、writer欄を用意して、自分を入れました。
ここで注意するのが、urlもTextで用意することです。

URLもあるのですが、APIを通してデータを取得した時に、Not Supportedの文字列が入ってきてしまいます。

Notionからデータを取得する

Notionをブログとして公開する、notion-blogという素敵なものもありますが、
今回はDBとしてNotionを使用したいので、こちらの記事を参考にしました。
現在、Notionの公式なAPIはないようで、非公式なものを使います。
使用したのはnotion-api-workerです。

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

const { data } = await $axios.get(
      `https://notion-api.splitbee.io/v1/table/${process.env.PAGE_ID}`,
      {
        headers: { Authorization: `Bearer ${process.env.TOKEN}` },
      }
    )

これでデータを取得できました。
配列の中にオブジェクトで入ってきます。

[
  {
    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/

vuetifyのカレンダーを使用しました。
通常であれば、<前の月次の月>のように遷移するボタンを用意するのですが、今回はヘッダにデータのある月のリンクだけ用意しています。

URLの指定

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

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

nuxt.config.js
  generate: {
    routes() {
      return ['/202011']
    },
  },

これだけでリンクを貼っている3ページ分が静的に生成されました。

余談ですが、リンクの値を間違って貼ってしまうと、generate時にエラーが起きてしまいますので気をつけましょう。(自戒。原因が分からず、調査してクロールに気づきました。数時間溶けた。)

Netlifyでホスティングする

ローカルで環境変数をdirenvで使っていたのですが、Netlifyの方でも設定が必要です。


(すっかり忘れていてページの生成時にAPIにアクセスできずに500になってしまいました。)
ちなみに、Nuxt.jsの困ったところなのですが、500でページの生成が失敗したとしても、正常終了してそのままデプロイしてしまいます。

オプションでエラー時にビルドを失敗させることができるので、--fail-on-errorをつけておいた方が無難です。

あと、keyの隠蔽は忘れずにしておきましょう。
PAGE_IDとTOKENがあれば誰でもデータが取得できてしまいます。
こちらの記事を参考に、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