【自作ブログ】Contentfulから記事を取得しよう
連載第4回目です。
今回はいよいよContentfulから記事を取得するところまで進めていきます。
今まで下準備してきたNetlify、Contentful、そしてNuxt.jsが全て繋がります。
Nuxtの説明も交えて進めていきますので、少しテンポが悪くなりますがご了承ください。
今回の作業の進め方
今回は以下の手順で進めていきます。
- 簡単なレイアウトを整える(ナビゲーションバーを追加)
- 記事を表示するコンポーネントを作る
- Contentfulの記事を取得する準備
- Contentfulの記事を表示する
- Netlifyにデプロイする
簡単なレイアウトを整える
さすがに何も無いのは寂し過ぎるので、ナビゲーションバーくらいは作っておくことにします。
必須ではないので不要の方はスキップしても問題ありません。
ナビゲーションバーを追加する
はじめにナビゲーションバーのコンポーネントを作っていきます。
Nuxtのコンポーネント(画面上の部品)はcomponents/
配下に置くルールになっているので、components/Navbar.vue
を新規追加してナビゲーションバーコンポーネントを作ります。
ナビゲーションバーのコンポーネントを追加
$ touch components/Navbar.vue
components/Navbar.vue
<template>
<b-navbar class="is-info">
<template slot="brand">
<b-navbar-item :to="{ path: '/' }" tag="router-link">
<strong class=" is-size-3-desktop"><i>Sample Blog</i></strong>
</b-navbar-item>
</template>
</b-navbar>
</template>
<script>
export default {
}
</script>
<style>
</style>
<b-navbar>
はBuefyで使えるタグになります。
詳しくはこちらに記載されていますが、レスポンシブなナビゲーションバーを表示することができます。
デフォルトレイアウトを変更
次にレイアウトファイルを修正してナビゲーションバーのコンポーネントを表示できるようにします。
layouts/
配下にあるvueファイルは画面を描画する際のレイアウトとして認識されます。
中でもlayouts/default.vue
は特別で、ビュー側のテンプレート(pages/
配下のvueファイル)でlayoutを指定しない場合は、自動的にlayouts/default.vue
のレイアウトが適用されるようになっています。
layouts/default.vue
<template>
<div>
<navbar />
<section class="container">
<div class="columns is-mobile">
<div class="column main-page-contents">
<nuxt />
</div>
</div>
</section>
</div>
</template>
<script>
import Navbar from '@/components/Navbar.vue'
export default {
components: {
Navbar
}
}
</script>
<style scoped>
#body-contents {
margin-top: 2em;
}
</style>
先ほど作ったナビゲーションバーをimport
で読み込んでcomponents
に登録しています。ちなみに@/components/Navbar.vue
は~/components/Navbar.vue
でも大丈夫です。
あとはテンプレート内でナビゲーションバーコンポーネントを<navbar />
で表示するようにしています。
画面で確認すると以下のように表示されます。
記事を表示するカードを作る
いつまでも表示されているHello world
の代わりに記事を表示するカード形式のコンポーネントを作っておきます。
components/Card.vue
というファイルがすでに存在していると思いますので、それを編集していきます。(無い場合は追加してください)
components/Card.vue
<template>
<div class="box is-radiusless">
<article class="media">
<figure class="media-left">
<div v-if="post.fields.headerImage">
<p class="image is-128x128">
<img :src="post.fields.headerImage.fields.file.url" alt="thumbnail">
</p>
</div>
<div v-else>
<p class="image is-128x128">
<img src="https://bulma.io/images/placeholders/128x128.png" alt="thumbnail">
</p>
</div>
</figure>
<figure class="media-content">
<div class="content">
<div class="is-size-4">
{{ post.fields.title }}
</div>
<div class="has-text-right">
<small>{{ getFormattedDate(post.fields.publishedAt) }}</small>
</div>
</div>
</figure>
</article>
</div>
</template>
<script>
export default {
props: {
post: {
type: Object,
reqire: true,
default: () => {
return {
fields: {
title: 'sample',
publishedAt: new Date(),
headerImage: null
}
}
}
}
},
methods: {
getFormattedDate (date) {
const originDate = new Date(date)
const year = originDate.getFullYear()
const month = originDate.getMonth() + 1
const day = originDate.getDate()
return `${year}年${month}月${day}日`
}
}
}
</script>
<style scoped>
.box {
box-shadow: 0.5em;
margin-bottom: 10px;
}
</style>
props
にて親コンポーネントから表示内容を受け取るように実装しています。
次にHello world
の代わりに上記のコンポーネントを表示するようにpages/index.vue
を修正します。
pages/index.vue
<template>
<div>
<card v-for="(post, index) in posts" :key="index" :post="post" />
</div>
</template>
<script>
import Card from '@/components/Card.vue'
export default {
components: {
Card
},
data () {
return {
posts: [
{
// 1件目
fields: {
title: 'これはテストです',
publishedAt: new Date()
}
},
{
// 2件目
fields: {
title: 'これはテスト2です',
publishedAt: new Date()
}
}
]
}
}
}
</script>
テスト用のデータを2件用意しておきました。画面で確認してみましょう。
いいですね。これでContentfulから取得したデータを表示できそうです。
Contentfulからデータを取得する
それでは今回のメインです。
まず公式に記載されている方法でJavascript用のSDKをインストールします。
$ npm install --save contentful
Contentfulのアクセスキーを環境変数に設定する
続いてContentfulへの接続に必要なアクセスキーを環境変数に設定します。
まずはContentfulのマイページ上部メニューの「Settings」の「API Key」を選択します。
「Example Key 1」というキーがプリセットされているはずなので、今回はこれを使います。
「Example Key 1」をクリックすると以下のアクセスキーが表示されるので、この値を.env
ファイルに定義していきます。
- Space ID
- Content Delivery API
- Content Preview API
プロジェクトの直下に.env
ファイルを作成します。
$touch .env
そして先ほど確認したContentfulのアクセスキーを登録します。
公式では.contentful.json
を使った方法がとられていますが、ここでは.env
を使います。
なお、.env
ファイルはGitHubなどのリポジトリにpushする際に無視されるようになっていますので、ご安心を。
.env
CTF_SPACE_ID=<Space ID>
CTF_CDA_ACCESS_TOKEN=<Content Delivery API>
CTF_PREVIEW_ACCESS_TOKEN=<Content Preview API>
※.env
に値を設定する場合はダブルクォート(")で囲む必要はありません。
続いてnuxt.config.js
にenv
プロパティを追加して、.env
に定義した環境変数を読み込めるようにします。
nuxt.config.js
require('dotenv').config()
export default {
~中略~
env: {
CTF_SPACE_ID: process.env.CTF_SPACE_ID,
CTF_CDA_ACCESS_TOKEN: process.env.CTF_CDA_ACCESS_TOKEN,
CTF_PREVIEW_ACCESS_TOKEN: process.env.CTF_PREVIEW_ACCESS_TOKEN
},
~中略~
}
Contentful SDKクライアントを生成するpluginを作る
次にNuxtのプラグイン機能(共通の処理などを定義したJSファイルを読み込む)を使ってSDKクライアントを生成する処理を実装します。公式のチュートリアルに倣ってplugins/contentful.js
を追加して編集します。
$ touch plugins/contentful.js
plugins/contentful.js
const contentful = require('contentful')
const defaultConfig = {
space: process.env.CTF_SPACE_ID,
accessToken: process.env.CTF_CDA_ACCESS_TOKEN
}
const sdkClient = contentful.createClient(defaultConfig)
export default sdkClient
これでContentfulからデータを取得するためのSDKクライアントを生成する準備は整いました。
さっそくpluginを利用して記事のデータを取得してみましょう。
pages/index.vue
<template>
<div>
<card v-for="(post, index) in posts" :key="index" :post="post" />
</div>
</template>
<script>
import Card from '@/components/Card.vue'
import sdkClient from '@/plugins/contentful.js'
export default {
components: {
Card
},
async asyncData ({ env }) {
let posts = []
await sdkClient.getEntries({
content_type: 'blogPost',
order: '-fields.publishedAt'
}).then((res) => {
posts = res.items
}).catch(console.error)
return { posts }
}
}
</script>
pluginをインポートして取得したSDKクライアントを用いてasyncData
メソッド内でContentfulからデータを取得しています。
asyncData
メソッドはページコンポーネントがロードされる前に実行されます。
実際にContentfulに問合せている処理はsdkClient.getEntries
メソッドになります。
await sdkClient.getEntries({
content_type: 'blogPost',
order: '-fields.publishedAt'
})
引数に渡しているオブジェクトのcontent_type
には前回作成したContent modelのContent type IDである「blogPost」を指定します。
order
はその名の通りソートを指定できますが、頭に-
を付けることで逆順(DESC)にすることができます。そのため、今回は「公開日が新しい順」にデータを取得しています。
では最後にちゃんとデータが取れているか画面でも確認してみましょう。
やりましたね。これで自由自在にContentfulからデータを取得できるようになりました。
Netlifyにデプロイする
最後にここまでの成果をNetlifyにデプロイしておきます。
GitHubにpush
まずはGitHubにpushしていきます。
$ git add -A
$ git commit -m "Contentfulからデータを取得する処理を実装"
$ git checkout master
$ git push origin master
Netlifyに環境変数をセットする
ここで忘れてはいけないのは.env
ファイルはGitHubにpushされないことです。
.env
ファイルで設定した内容と同じものをNetlifyの環境変数にも設定していきます。
Netlifyの管理ページ上部のメニューの「Settings」から「Build & Deploy」 → 「Environment」を選択します。そして「Edit variables」をクリックします。
キーと値のカラムが表示されるので、必要な値を設定して「Save」しましょう。
あとは環境変数を反映させるためにもう一度デプロイする必要があるので、
ページ上部のメニューの「Deploys」から「Trigger deploy」→「Deploy site」を選択して手動でデプロイを実行します。
Netlifyのビルドが終わったのを確認してサイトのURLにアクセスして確認してみましょう。先ほどローカルで確認したのと同じようにContentfulの記事の内容が表示されていればバッチリです。
終わりに
お疲れ様でした。ついにNetlify、Contentful、Nuxt.jsが繋がりましたね。
次回は記事の詳細画面を作っていきたいと思います。
更新の告知はTwitterで行っていますので、ぜひフォローもお願いします!
それではまた次回。