Contentfulの料金と使い方を整理しつつ、Nuxt.jsと組み合わせてブログを作る
Contentfulの料金と使い方を整理しつつ、Nuxt.jsと組み合わせてブログを作る:
Contentfulを使ってみたくなったので、印象に残った邦画を書き残すブログを作りました。ブログを作って満足してしまったので、記事の中身は(仮)です。Contentfulの考え方に馴染むのに少し時間がかかったので、そこのところの整理がメインの記事です。
https://blog.houga.cc
CMSというと、WordPressとMovable Typeぐらいしか知らなかったのですが、最近ヘッドレスCMSという言葉を耳にするようになりました。ヘッドレスCMSは、WordPressのようにテンプレートを表示する部分を持たず、APIでデータを提供することに特化している点が特徴です。
ヘッドレスCMSの選択肢は、こちらのサイトにたくさんありましたが、そのなかで、ContentfulというCMSのサービスが気になったので、Nuxt.jsと組み合わせて簡素なブログを作りました。
headlessCMS | A List of Content Management Systems for JAMstack Sites
ものは言いような気もするけれど、CMSではなくContent Infrastructureらしい。
ドキュメントも見やすくて素敵。
https://www.contentful.com
https://www.contentful.com/pricing/
アカウントの作成時に、MICRO SPACEというものをひとつ割り当ててもらえます。個人で使う分にはMICRO SPACEで事足りそうなので、かなり気前がいい印象です。
レコード数は、エントリーとアセットを合わせた数になるようで、たとえばブログエントリーが10件あって、5つの画像を使用している場合は、15レコードになります。スペースを追加したくなった場合や、より大きなスペースを使いたくなった場合は、お金が必要です。
また、Fair Use PolicyでAPIの呼び出し数や、アセットの帯域の制限が決められています。画像などの数が多く、かなりのアクセスが見込まれる場合は、アセットの帯域が上限に達するかもしれません。
https://www.contentful.com/r/knowledgebase/fair-use/
引っかかることはないと思いますが、Technical Limitsもあるので参考までに。
https://www.contentful.com/developers/docs/technical-limits/
気になる部分だと思うので、できる限り細かく書いていますが、プラン内容が変更されることもあると思うので、実際に使う前には必ず公式サイトを確認してください!
https://www.contentful.com/pricing/
サインアップから指示通りに進んでいけばスムーズにできたので、この手順は省略します。
https://www.contentful.com/sign-up/
プロジェクトごとに割り当てる領域のことです。
このスペース上に、コンテンツモデルを定義していきます。
コンテンツモデルは、すべてのコンテンツを束ねる概念です。
そのモデルのなかに、「Post」や「Tag」など、コンテンツの雛形となるコンテンツタイプを作成し、そこにフィールドを追加していく流れになります。
今回は、印象に残った邦画を書き残すブログを作りたいので、「Post」という名前のコンテンツタイプを作成し、映画のタイトルや公開日、感想などのフィールドを追加しました。データの種類やバリデーションなどを直感的に選べるので、説明をあまり読まなくてもサラッと進められて素敵です。
Content trees, tags, and facets in Contentful
今回は試せていませんが、
「Use the API」からアクセストークンの設定ページに移動して作成します。
この画面にある、
Contentfulの設定が一通り終わったので、フロントエンドの実装をしていきます。
ドキュメントに従ってインストールします。
この記事を書いている時点で、Nuxt.jsのバージョンは
インストール - Nuxt.js
作成したプロジェクトに移動して、開発サーバーを起動します。
JavaScript用のSDKが用意されているので、それを使って記事を取得してみます。
APIに関する処理はそれなりに増えそうだったので、
一覧の取得はできましたが、「Post」と「Tag」のコンテンツタイプが一緒に取得されてしまっているので残念な感じです。
ドキュメントのSearch parametersを参考に、
参照型の「Tag」の
Filter API results with relational queries
Reverse order
skipにオフセット値を指定して、limitに件数を指定すると、ページに分けてデータを取得できます。
あとはひたらすらページのコーディングをしていきます。今回のブログは、とにかく簡素にしたかったので、表示項目を最小限に絞りました。見た目に関しては特に書くことがないので省略しますが、コードをGitHubにアップしています。
https://github.com/noplan1989/houga-blog
設定が終わったら、コマンドを実行して静的サイトを出力し、表示を確認します。
あとは好きなところへホスティング。
CloudFront+S3の環境が好きなので、CircleCI経由でデプロイするように設定しました。ここは、人によってホスティング先が違うと思うので省略しますが、AWSを使いたい方は別の記事に書いているので、参考までに。
Nuxt.js+CircleCIで静的ページをAWSのS3へデプロイする
Contentfulの管理画面のSettings → Webhooksから設定できます。
CircleCIのテンプレートが用意されていたので、CircleCIの管理画面からAPIのトークンを取得して、画面の指示通りに設定していけば無事に連携できました。どのコンテンツタイプが変更されたらフックするかなどを細かく設定できて便利です。
Webhooks | Contentful
Managing API Tokens | CircleCI
Nuxt.jsの
どうせPublicなコンテンツなので、データが欲しければアクセストークンを自由に使ってくれというスタンスで。今回の場合は、ただのブログなので誰に見られても問題のないコンテンツですが、会員サイトのコンテンツを扱う場合は、Nuxt.jsにアクセストークンを設定してしまうと、漏れた時にコンテンツが垂れ流しになってしまうのでマズいです。
そもそも会員サイトならサーバー側で認証が入るはずなので、Nuxt.jsにアクセストークンを置くようなことはしないと思いますが。
Contentfulを使ってみて、その使いやすさや柔軟性には感動しましたが、「WordPressはもう古い!これからの時代はContentful!」などと言うつもりはサラサラなく、ブログをサクッと作りたいときには、これからもWordPressを使うと思います。プラグインが豊富だったり、運用担当の人が操作に慣れていたりで、なんだかんだ融通が効くので。一方、個人的にWordPressのコードを書いている時間はあまり楽しくないので、仕事以外では別のCMSを使ってバランスをとりたいというのが、正直なところです。
ブログを作って満足してしまって、記事がまだ(仮)なので、そのうち書きたい。
ブログ
https://blog.houga.cc
ソースコード
https://github.com/noplan1989/houga-blog
Contentfulを使ってみたくなったので、印象に残った邦画を書き残すブログを作りました。ブログを作って満足してしまったので、記事の中身は(仮)です。Contentfulの考え方に馴染むのに少し時間がかかったので、そこのところの整理がメインの記事です。
https://blog.houga.cc
ヘッドレスCMSというもの
CMSというと、WordPressとMovable Typeぐらいしか知らなかったのですが、最近ヘッドレスCMSという言葉を耳にするようになりました。ヘッドレスCMSは、WordPressのようにテンプレートを表示する部分を持たず、APIでデータを提供することに特化している点が特徴です。ヘッドレスCMSの選択肢は、こちらのサイトにたくさんありましたが、そのなかで、ContentfulというCMSのサービスが気になったので、Nuxt.jsと組み合わせて簡素なブログを作りました。
headlessCMS | A List of Content Management Systems for JAMstack Sites
Contentful
Contentful is not a CMS, Contentful is content infrastructure.Webサイトがシンプルで見やすい。
ものは言いような気もするけれど、CMSではなくContent Infrastructureらしい。
ドキュメントも見やすくて素敵。
https://www.contentful.com
無料で使える範囲と制限
https://www.contentful.com/pricing/
アカウントの作成時に、MICRO SPACEというものをひとつ割り当ててもらえます。個人で使う分にはMICRO SPACEで事足りそうなので、かなり気前がいい印象です。
- 24個のコンテンツタイプ
- 5000個のレコード
- 10人のユーザー
- 1つのロール(ユーザー権限)
- 2つの環境(master/stagingとか)
- 2つのロケール(多言語対応)
レコード数は、エントリーとアセットを合わせた数になるようで、たとえばブログエントリーが10件あって、5つの画像を使用している場合は、15レコードになります。スペースを追加したくなった場合や、より大きなスペースを使いたくなった場合は、お金が必要です。
また、Fair Use PolicyでAPIの呼び出し数や、アセットの帯域の制限が決められています。画像などの数が多く、かなりのアクセスが見込まれる場合は、アセットの帯域が上限に達するかもしれません。
- APIの呼び出し - 200万/月
- アセットの帯域 - 0.75TB/月
Extra API calls will be billed at \$5/1,000,000 API calls/month. Extra asset bandwidth consumption will be billed at \$65/1 TB/month.超過分はこんな感じで料金が発生します。
https://www.contentful.com/r/knowledgebase/fair-use/
引っかかることはないと思いますが、Technical Limitsもあるので参考までに。
https://www.contentful.com/developers/docs/technical-limits/
気になる部分だと思うので、できる限り細かく書いていますが、プラン内容が変更されることもあると思うので、実際に使う前には必ず公式サイトを確認してください!
https://www.contentful.com/pricing/
サインアップから利用開始まで
サインアップから指示通りに進んでいけばスムーズにできたので、この手順は省略します。https://www.contentful.com/sign-up/
スペース
プロジェクトごとに割り当てる領域のことです。このスペース上に、コンテンツモデルを定義していきます。
コンテンツモデル
コンテンツモデルは、すべてのコンテンツを束ねる概念です。
そのモデルのなかに、「Post」や「Tag」など、コンテンツの雛形となるコンテンツタイプを作成し、そこにフィールドを追加していく流れになります。
今回は、印象に残った邦画を書き残すブログを作りたいので、「Post」という名前のコンテンツタイプを作成し、映画のタイトルや公開日、感想などのフィールドを追加しました。データの種類やバリデーションなどを直感的に選べるので、説明をあまり読まなくてもサラッと進められて素敵です。
タグを設定したい
How do I categorize my content?Contentfulはブログサービスではないので、デフォルトではカテゴリやタグが用意されていませんが、コンテンツタイプとして「Tag」を作成して、それを「Post」から参照することで実現できます。この柔軟さは魅力的です。
In Contentful there are two ways to create categories, either using short text fields or using Reference fields to other entries.
Basics - FAQ
Content trees, tags, and facets in Contentful
複数の環境やプレビューのAPIなど
今回は試せていませんが、master以外の環境を作れたり、ドラフトの記事を取得できるプレビューのAPIがあったりで、色々と他にも使えそうな機能があったので、また使う機会があったら試してみたい。
APIの準備
「Use the API」からアクセストークンの設定ページに移動して作成します。
この画面にある、
Space IDとContent Delivery API - access tokenは、のちほど必要になります。
Nuxt.js
Contentfulの設定が一通り終わったので、フロントエンドの実装をしていきます。
アプリケーションの作成
ドキュメントに従ってインストールします。この記事を書いている時点で、Nuxt.jsのバージョンは
2.2 です。$ npx create-nuxt-app <project-name>
開発を始める
作成したプロジェクトに移動して、開発サーバーを起動します。
$ cd <my-project> $ npm run dev
APIで記事を取得してみる
JavaScript用のSDKが用意されているので、それを使って記事を取得してみます。
APIに関する処理はそれなりに増えそうだったので、
/apiディレクトリを作成して処理をまとめました。spaceとaccessTokenには、先ほど準備したものを指定しますが、@nuxtjs/dotenvあたりを使って、環境変数に設定して使用するのが良いと思います。一覧の取得はできましたが、「Post」と「Tag」のコンテンツタイプが一緒に取得されてしまっているので残念な感じです。
# SDKの追加 $ npm install --save contentful
/api/index.js
import { createClient } from 'contentful'
const client = createClient({
space: process.env.SPACE_ID,
accessToken: process.env.ACCESS_TOKEN
})
export const fetchEntries = () => client.getEntries()
/pages/index.vue
<template>
<ul>
<li v-for="item in items" :key="item.sys.id">{{ item.fields.title }}</li>
</ul>
</template>
<script>
import { fetchEntries } from '@/api'
export default {
async asyncData() {
return await fetchEntries()
}
}
</script>
コンテンツタイプを指定して取得する
ドキュメントのSearch parametersを参考に、
content_typeを指定して絞り込むと、思い通りの表示になりました。/api/index.js
export const fetchEntries = content_type => client.getEntries({ content_type })
/pages/index.vue
<script>
export default {
async asyncData() {
return await fetchEntries('post')
}
}
</script>
タグのIDで絞り込んで、公開日でORDER BY DESC
参照型の「Tag」のidで絞り込んで、releaseDateのフィールドで降順の並び替えをする例です。ネストしている場合も直感的に指定できてすごい。降順(DESC)にしたい場合は、orderの値に-を付けるといけます。APIの設計する人が大変そう。Filter API results with relational queries
Reverse order
export const fetchPostsByTagId = id =>
client.getEntries({
content_type: 'post',
'fields.tags.sys.id': id,
order: '-fields.releaseDate'
})
ページネーション
skipにオフセット値を指定して、limitに件数を指定すると、ページに分けてデータを取得できます。const POSTS_PER_PAGE = 30
export const fetchPosts = page =>
client.getEntries({
content_type: 'post',
order: '-fields.releaseDate',
skip: (page - 1) * POSTS_PER_PAGE,
limit: POSTS_PER_PAGE
})
見た目を整える
あとはひたらすらページのコーディングをしていきます。今回のブログは、とにかく簡素にしたかったので、表示項目を最小限に絞りました。見た目に関しては特に書くことがないので省略しますが、コードをGitHubにアップしています。
https://github.com/noplan1989/houga-blog
動的なルートの明示
generateコマンドでは 動的なルーティング は無視されます。Nuxt.jsで静的サイトを生成する際に、
generateプロパティ
/entry/_idのような動的なルートは、設定ファイルで明示してあげる必要があります。Nuxt.jsから見たら、ビルド時にどんなIDのエントリーがあるかは知る由もないので、APIで取得してルートを網羅して返すようにします。nuxt.config.js
import { createClient } from 'contentful'
require('dotenv').config()
export default {
generate: {
routes: async function () {
const client = createClient({
space: process.env.SPACE_ID,
accessToken: process.env.ACCESS_TOKEN
})
const { items } = await client.getEntries({
content_type: 'post',
limit: 1000 // 最大
})
return items.map(item => `/entry/${item.sys.id}`)
}
}
}
静的サイト生成
設定が終わったら、コマンドを実行して静的サイトを出力し、表示を確認します。$ npm run generate
デプロイ
あとは好きなところへホスティング。
CircleCIでビルドしてAWSのS3へアップ
CloudFront+S3の環境が好きなので、CircleCI経由でデプロイするように設定しました。ここは、人によってホスティング先が違うと思うので省略しますが、AWSを使いたい方は別の記事に書いているので、参考までに。Nuxt.js+CircleCIで静的ページをAWSのS3へデプロイする
Contentfulの記事更新をきっかけにCircleCIを起こす
Contentfulの管理画面のSettings → Webhooksから設定できます。
CircleCIのテンプレートが用意されていたので、CircleCIの管理画面からAPIのトークンを取得して、画面の指示通りに設定していけば無事に連携できました。どのコンテンツタイプが変更されたらフックするかなどを細かく設定できて便利です。
Webhooks | Contentful
Managing API Tokens | CircleCI
アクセストークンとブラウザで再会
Nuxt.jsのgenerateで静的サイトを生成した場合、ページ遷移時はSPAのようにふるまうので、APIの通信が発生します。そのため、ブラウザを少しのぞくだけで、環境変数に設定したSPACE_IDやACCESS_TOKENが確認できてしまいます。The Content Delivery API (CDA), available at cdn.contentful.com, is a read-only API for delivering content from Contentful to apps, websites and other media.幸いContent Delivery APIはread-onlyなので、不正なコンテンツの投稿や改ざんをされる心配はありませんが、どうも気持ちが悪いです。アクセストークンなどが絡む処理はサーバーサイドで実装するのが筋だとは思いますが・・・面倒になってしまったので、ブログはこのままにしました。
Content Delivery API
どうせPublicなコンテンツなので、データが欲しければアクセストークンを自由に使ってくれというスタンスで。今回の場合は、ただのブログなので誰に見られても問題のないコンテンツですが、会員サイトのコンテンツを扱う場合は、Nuxt.jsにアクセストークンを設定してしまうと、漏れた時にコンテンツが垂れ流しになってしまうのでマズいです。
そもそも会員サイトならサーバー側で認証が入るはずなので、Nuxt.jsにアクセストークンを置くようなことはしないと思いますが。
WordPress vs Contentful ではない
Contentfulを使ってみて、その使いやすさや柔軟性には感動しましたが、「WordPressはもう古い!これからの時代はContentful!」などと言うつもりはサラサラなく、ブログをサクッと作りたいときには、これからもWordPressを使うと思います。プラグインが豊富だったり、運用担当の人が操作に慣れていたりで、なんだかんだ融通が効くので。一方、個人的にWordPressのコードを書いている時間はあまり楽しくないので、仕事以外では別のCMSを使ってバランスをとりたいというのが、正直なところです。ブログを作って満足してしまって、記事がまだ(仮)なので、そのうち書きたい。
ブログ
https://blog.houga.cc
ソースコード
https://github.com/noplan1989/houga-blog
コメント
コメントを投稿