TumblrブログにJamstackなフロントページを作ってみた
Introduction
10年くらい前に何となく立ち上げ、ここ数年は主にフォトブログ的な用途で使っていたtumblr。 過去に当ブログでも何度か触れた通り、tumblr標準で用意されている独自タグ+JavaScriptでカスタマイズロジックを追加することで、標準で用意されている範囲内でもかなり自由度の高いブログフロントページを作成することが可能で気に入っていました。が、ここ数年の中で、
- 投稿形式に大幅な仕様変更が入り都度カスタマイズロジックを修正する手間が大きい
- そのたびにクライアントサイドで実行される処理が肥大化していき、ページの表示速度が遅くなる
- 他で取得した独自ドメインを使用できない(tumblr内で取得するか、tumblrにドメイン移管する必要がある)
等々、不自由・不満に感じる点がいくつかでてきて。いっそのことAPI叩いてデータだけ取得して、別途フロントページを作ってしまえば?と思いつき、年末年始休暇に試行錯誤、一旦形になるところまで来ました。
そんな試行錯誤の過程をいつも通り自分向けの備忘として綴ってみる。
技術スタック
いうほど大したものではありませんが。。。
- フロントエンド
- フレームワーク:Nuxt3
- 言語:TypeScript
- UIライブラリ:Vuetify3
- レンダリング方式:SSG
- プラットフォーム:Netlify
- バックエンド
- プラットフォーム:Tumblr
事前準備
TumblrのAPIを叩くためには事前に開発アプリケーション登録してAPIキーを取得する必要があります。下記から開発アプリケーション登録をします。
Tumblr APIには、APIキーで実行可能な操作(主に照会系操作)とユーザによるOAuth認証が必須となる操作(主に更新系操作)があります。今回はフロントエンドページに表示するデータを照会する目的なので、APIキーのみで実行可能な範囲で実装していきます。
アプリケーション登録後に発行されるOAuth Consumer KeyがAPIキーに該当します。Sercret KeyはOAuth認証時に必要になるものなので、今回は使用しません。外部に公開しないよう保管しておきましょう。
API簡易ガイド
今回 私が使用したAPIの呼び方を記載します。
ブログinfo
https://api.tumblr.com/v2/blog/<ブログID>/info?api_key=<APIキー>
エンドポイント:info を使用することでブログの基本情報を取得できます。<ブログID>には自身のTumblrブログのID xxx.tumblr.com
を、<APIキー>には上記で取得したOAuth Consumer Keyを指定の上、HTTP GETして使用します。
POST一覧取得
https://api.tumblr.com/v2/blog/<ブログID>/posts?api_key=<APIキー>
エンドポイント:posts を使用すると、POST情報が一覧で取得できます。件数指定・範囲を何も指定しないと最新20件がデフォルトで取得されます。件数指定はlimitオプション、範囲指定はoffsetオプションで指定します、よくあるREST APIの形式ですね。
私の場合、1ページに6個のPOSTを表示する形式にしているので、
1ページ目は、offset=0でこんな感じ、1POST目から6POST目が取得されます。
https://api.tumblr.com/v2/blog/<ブログID>/posts?api_key=<APIキー>&limit=6&offset=0
2ページ目は、offset=6でこんな感じ、7POST目から12POST目が取得されます。
https://api.tumblr.com/v2/blog/<ブログID>/posts?api_key=<APIキー>&limit=6&offset=6
ページ数からoffset値は、
offset = limit * (ページ数 - 1)
から算出できます。
単一POST取得
https://api.tumblr.com/v2/blog/<ブログID>/posts?api_key=<APIキー>&id=<POST ID>
にPOSTのID(一覧取得でとってきたもの、または任意のブログページのURLに組み込まれている18桁の数値)を指定することで、該当するPOSTのみが取得できます。
Nuxt3へ組み込み時の落とし穴
あとは通常のJamstackページを構築するときと同様、Nuxt3開発環境をセットアップし、上記APIをキック→画面に表示させるだけなので、詳細はここでは割愛。と軽く考えていましたが、Tumblr APIの仕様にいくつか落とし穴があったので、書き留めておきます。
APIレスポンスがPOSTタイプに応じて激しく変動。。。
APIのレスポンスから、タイトル・アブストラクト・アイキャッチ画像・本文を取得して、画面にマッピングさせるだけ、なのですが。。。実際に実装してみるとnull exceptionの嵐。原因を探っていくとTumblrのPOSTタイプが悪さをしていることがわかりました。
Tumblrには数年前まで使われていたLegacy Post Format(LPF)と、現在標準のNeue Post Format(NPF)が存在します。このうちLPFは投稿時に、テキスト・画像・リンクetcといったPostタイプを指定するものでした。この時に指定できる情報がまちまち、かつ物理名もバラバラなものをAPIとして公開されているため。。。
一例をあげると、
- LPFの画像形式の場合
- titleは設定されていない = 常にnull
- 本文は、caption に設定されている、bodyという要素もあるがここは常にnull
- caption_abstract にはアブストラクトが設定されているときもあれば、入っていないときもある
- LPFのリンク形式の場合
- titleは設定されている
- 本文は、description に設定されている、bodyやcaptionは常にnull
- description_abstract にアブストラクトが設定されているときもあれば、入っていないときもある
といった具合。
結果的になかなか残念な分岐がマッピング処理に入ってしまいました。
- POSTタイプがLPF 画像形式の場合
- caption_abstract が設定されている場合
- caption_abstract 中の画像をアイキャッチにマッピング
- caption_abstract 中の1つ目のh1要素をタイトルにマッピング
- caption を本文にマッピング
- caption_abstract をアブストラクトにマッピング
- caption_abstract がnullの場合
- caption 中の1枚目の画像をアイキャッチにマッピング
- caption 中の1つ目のh1要素をタイトルにマッピング
- caption を本文にマッピング
- caption の1ブロック目をアブストラクトにマッピング
- caption_abstract が設定されている場合
- POSTタイプがLPF リンク形式の場合
- description_abstract が設定されている場合
- description_abstract をアブストラクトにマッピング
- description を本文にマッピング
- title をタイトルにマッピング
- description_abstract がnullの場合
- description の1ブロック目をアブストラクトにマッピング
- description を本文にマッピング
- titleをタイトルにマッピング
- description_abstract が設定されている場合
- POSTタイプがLPF テキスト形式、またはNPFの場合
- body_abstract が設定されている場合
- body_abstract 中の画像をアイキャッチにマッピング
- body_abstract をアブストラクトにマッピング
- body を本文にマッピング
- title をタイトルにマッピング
- body_abstract がnullの場合
- body_ 中の1枚目の画像をアイキャッチにマッピング
- body の1ブロック目をアブストラクトにマッピング
- body を本文にマッピング
- title をタイトルにマッピング
- body_abstract が設定されている場合
単一POST取得時のID桁落ち - id_stringを使おう
POST IDを使用して単一POSTを取得するよう組み込んでみたところ、どのページを指定してもそんなページ存在しないよ、とエラーが返されました。
確認してみたところ、
APIリクエスト期待値:760873167322497024
APIリクエスト設定値:76087316732249702
と一桁桁落ちした状態でAPIをキックしていることが分かりました。
このIDは最初にAPIでPOST一覧を取得し、そこから得られたIDを渡しているのですが、
- POST一覧取得APIからは数値型として返却される
- JavaScriptがAPIレスポンスをパースしてオブジェクト化するときにNumber型に暗黙的に変換、でもNumber型では1桁足りないため桁落ち
という状態になっていました。
これにはかなり頭を悩ませる。パース時に暗黙的に変換されてしまうところなので手の入れようがなく、自力でJSONをパースするロジックを書くしかない?すごくしんどいのですが。。。とAPIレスポンスを眺めていたところ、idフィールドの下にid_stringという文字列形式で渡してくれる項目を見つけました。これを使うことで文字列扱いになるので桁落ち問題が解消、idからPOSTを取得できるようになりました!
日付フォーマット変換時の互換エラー
日付のフォーマットにdayjsというライブラリを使用しているのですが、なぜかappleデバイスで確認した場合のみ、フォーマット結果が invalid date になってしまいました。WindowsやAndroidでは正しく見える。
Copilot君に助けてもらいながら原因を調べてみたところ、Tumblr APIが返してくる日時形式 "2024-12-10 13:04:23 GMT" がappleデバイスでは日付として認識されず、結果 invalid date になった模様。
文字列置換を駆使して、一度 ISO8601形式("2024-12-10T13:04:23Z")に変換してからdayjsに渡すようしたことで解消しました。
"2024-12-10 13:04:23 GMT".replace(" ", "T").replace(" GMT", "Z");
終わりに
例によって例のごとく自己満足の備忘なので、読みづらくて申し訳ないです。いつも通りソースコードはGitHubに格納していますので、ご参考までに。
そういえば、昨年の年初、同じようにNuxt3+Jamstackについて綴った際の末尾に、ChatGPT等のAIツールに使われる・操られる のではなく、ツールを使いこなす ようになりたいと偉そうなことを宣っていましたが。。。実際のところ昨年1年でAIツールへの依存度がどんどん高くなったのは事実です。でも一応 AIのいっていることを全て信じていない、自分で実機検証したり、別アプローチで調べ直すことはやめていないので、まだ大丈夫かな。
AIによって調査にかかる時間が大幅に減ったことで、より別の視点・方法を考える余裕ができたのでその面でもプラスには働いていると思う。
いかにAIに追い越されない・取って代わられない創発のできる人間として価値を高めていくかが、今後の課題ね。
参考文献
Comments