この記事をおすすめしたい人
- Nuxt.js×microCMSでコンテンツ管理しようとしている人
- Nuxt.js×microCMSでブログを作ろうとしていて前後記事の取得に頭を悩ませている人
- つまりオレ
前回の記事で次は「目次の自動生成を書く」と言ったがアレは嘘だ!
何も知らない超初心者が脱WordPressしたくてNuxt.jsでサイト構築していくシリーズです。
既にWordPressサイトを作っている場合にはREST API利用でNuxt.jsを使うのがお手軽だとは思うんですが、最近microCMSという国産のヘッドレスCMSにぞっこんでして。
WordPressで簡単にできていたことを、Nuxt.js×microCMS環境でも実現する代替手段について調べていきます。
いや、別にWordPressが嫌いとか、WordPressに怨みがあるとか、それどころかWordPressには感謝しかないのですけれども、SPAを経験してしまうと二度と動的CMSには戻りたくないなと思っただけなのです。
今回はNuxt.js×microCMS環境で前後記事を取得する方法をお話しします。
WordPressの上でな!
※ このブログはまだWordPress製です
先にまとめ
前提として、この↓ようにそのページに表示する記事データを取得できているものとします。
export default {
async asyncData({ $config, params }) {
const { data } = await axios.get($config.apiRoot + '/blog/' + params.id, {
headers: { 'X-API-KEY': $config.apiKey }
})
return data
}
}
$configというのはAPIキーを隠す手段らしく、microCMS公式ブログで詳しく説明されてるのでそっちを見てください。 僕も真似てるだけです。
microCMSはね、国産ヘッドレスCMSなのもあってネイティブ日本語文献というだけでめちゃくちゃありがたいんですけど、公式ブログがチョー気合い入ってるんですよ。 NuxtやらNextやらが今後もっと流行るとして、それ用のCMSとして是非microCMSを使ってください!というのがめっちゃ伝わりました。
この辺の話はまた今度やります。
次の記事を取得するコード
この↓コードを上記asyncData内に追加すると、nextに次の記事のidとタイトル、公開日時が入ります。
let next = null
const resNext = await axios.get($config.apiRoot + '/blog/' +
'?limit=1' +
'&fields=id,title,publishedAt' +
'&orders=publishedAt' +
'&filters=publishedAt[greater_than]' + current.publishedAt, {
headers: { 'X-API-KEY': $config.apiKey }
})
if ( resNext.data.contents && resNext.data.contents.length > 0 ) {
next = resNext.data.contents[0]
}
前の記事を取得するコード
同様にasyncData内にこの↓コードを追加すると前の記事のデータを取得できます。
let prev = null
const resPrev = await axios.get($config.apiRoot + '/blog/' +
'?limit=1' +
'&fields=id,title,publishedAt' +
'&orders=-publishedAt' +
'&filters=publishedAt[less_than]' + current.publishedAt, {
headers: { 'X-API-KEY': $config.apiKey }
})
if ( resPrev.data.contents && resPrev.data.contents.length > 0 ) {
prev = resPrev.data.contents[0]
}
相違点はordersが降順になっている点、公開日時の比較演算子がgreater_thanからless_thanに変わっているくらいです。
以下、コードの詳細とか注意点とか。
基本的な考え方
現在の記事の公開日時にたいして、それ以降の中から最も古いものが次の記事、それ以前の中から最も新しい者が前の記事、としています。
なので前後で全く同じ公開日時だった場合、正確な情報を返しません。 あんまりないと思うけども。
これを取得するためのクエリの書き方をmicroCMS公式のAPIマニュアル読んで書いただけです。 この↓辺ですね。
'?limit=1' +
'&orders=-publishedAt' +
'&filters=publishedAt[less_than]' + current.publishedAt,
limitについて
指定条件の記事をいくつまで取得するか、という指定です。
前後記事を取得する場合、1記事しか必要ないのでlimit=1。
デフォルトがたかだか10なので別に指定しなくてもいいけど、APIの通信サイズは極力減らしたいので指定しています。
ordersについて
指定条件の記事をどういう順序で並び替えるか、という指定です。
次の記事を取得する場合は日付昇順で並んでもらう必要があるので、「orders=publishedAt」と指定します。
前の記事を取得する場合は降順なので「orders=-publishedAt」と指定します。
ordersに指定するキーにマイナス「-」を付けるだけで降順になるのは、操作しやすいし、感覚的にも分かりやすいし良いですね。
filtersについて
microCMS公式のAPIマニュアルを見ると、かなり細かく指定できるっぽいです。
今回は「現在の記事より新しい」=「publishedAt[greater_than] + current.publishedAt」、「現在の記事より古い」=「publishedAt[less_than] + current.publishedAt」と指定しています。
fieldsを指定してAPIレスポンスを軽量化
えー、microCMSから記事APIを取得するとそれぞれの記事データには以下の内容が含まれています。
- contents:
記事データの配列 - totalCount:
指定したクエリで取得出来る記事総数(たぶん) - offset:
指定したクエリで記事を取得し始める開始位置(たぶん) - limit:
指定したクエリで記事を取得する際の記事上限数(たぶん)
「たぶん」となっている部分は記事総数が少ないので「おそらくそうであろう」ってことです。
で、記事データ内の情報は、
- id:
記事固有のID。WordPressでいうところのスラッグ。 - createdAt:
記事を作成したタイムスタンプ。 - updatedAt:
記事を更新したタイムスタンプ。 - publishedAt:
記事を公開したタイムスタンプ。 - title:
記事のタイトル。僕が指定して作った項目です。 - content:
記事本文。僕が指定して作った項目です。
で、ね?
記事の個別ページを作る時にはidからcontentまで全部持っててもらっていいわけなんですけども、こんな感じの目次ページの場合は、URLを生成するためのIDとタイトル(とサムネイル)くらいでいいんですよね。
WordPressの時もこの問題に頭を悩ませましたが、目次ページを作るだけなのに本文のデータを持っててもらうと通信サイズがめっちゃ増えるんですよ。
WordPressのREST APIの時にはこの問題を解決するためにREST APIをカスタマイズするというクッソめんどくさい作業をやったわけですが、microCMSの場合はデフォルトで項目を絞る手段が用意されています。 素敵。 最高。 結婚しよ。
それが「fields」です。
fieldsにキーを指定すると、指定した要素だけAPIが返します。 サンプルのように「fields=id,title,publishedAt」と指定した場合、スラッグとタイトルと公開日時しか返しません。
WordPressのAPIレスポンスに頭を悩ませた身としてはこれは素晴らしい機能だと思います。
さいこう
APIの戻り値の処理
最初のサンプルコードのこの↓部分ですね。
if ( resPrev.data.contents && resPrev.data.contents.length > 0 ) {
prev = resPrev.data.contents[0]
}
上でも書いたように、条件指定でブログ一覧から絞り込んだ場合、以下のようなデータが返ります。
- contents:
記事データの配列 - totalCount:
指定したクエリで取得出来る記事総数(たぶん) - offset:
指定したクエリで記事を取得し始める開始位置(たぶん) - limit:
指定したクエリで記事を取得する際の記事上限数(たぶん)
今回欲しいデータは配列contentsの最初の要素です。
なので、resPrev.data.contents[0]をprevに代入しています。
最初の記事では次の記事が、最後の記事では前の記事が存在しないので、初期値をnullとしています。
generate時の処理
記事ページを生成する_id.vueや_slug.vueはAPIから取得したデータに対して動的にページを生成していくため、ビルド時には「どういうURLのページがどれくらい存在するか」というのがNuxt.js側には分かりません。
なので動的ルーティングに対してルートを追加する方法があるんですが、割と最近のアップデートでこれは必要なくなったようです。
ところがこれに頼るとですね。
最初に目次ページを生成するときにAPIと通信、個別のページを作る際にAPIと通信、と、100ページあった場合は単純に考えて最低でも101回通信する必要が出てくるわけです。
これを解決するためにNuxt.js側でペイロードという仕組みが用意されています。
大雑把に仕組みを説明すると、ビルド時にがばっとAPIから全データを取得してしまって、個別ページを生成する際にそのデータから必要な情報を渡す、という手法です。 APIと通信する回数を激減させることができます。
通信サイズを減らすとか、高速化するとか、
たまのビルド時だけのことなら別にそんなん気にせんでええやん。
と思ってたんですけどね、姉妹サイトのオレGAME.comはそれが原因で48時間くらいサイトを停止させてしまった実績があります。
なので…
データが肥える前に先に配慮しとけ!
時間ない中、真っ青な顔してメンテした身からすると、最初から考慮するのをおすすめしたいです。 ガチで。
ちょっとヘビーな話題なんで、これは次回にやりますね。
まとめ
以上です。
microCMSから前後記事を取得するだけなら最初のコードをコピペするだけで使えると思うんですが、API操作は今後も必要になってくるので、自分の意図した動作を自分で書けるようになってる方がいいのかなーとちょっと細かく書きました。
ここに書いたのも一部なので詳しく知りたい人はmicroCMS公式を見るのが一番いいと思います。
以上、WordPressからお届けしました!