microCMSで用意したデータをGridsomeで表示させる

microCMSは純日本製のHeadlessCMSで、分かりやすいUIと完全日本語対応が最高に使いやすいサービスです。

この記事ではGridsomeというSSGを使い、microCMSで用意したデータを取得し、GraphQLに変換し画面に表示するまでの流れをメモ代わりに書いていきたいと思います。

# 実装概要

流れとしては、
1. 『お知らせ』をmicroCMSに投稿
2. Gridsomeのサーバ起動時にmicroCMSからデータ取得
3. GraphQLに変換しindex.vueに一覧表示

していきたいと思います。

# microCMSでデータを準備

[こちらの手順](https://microcms.io/blog/getting-started/) に従い、お知らせデータの作成を行います。

APIスキーマ
![FireShot Capture 018 - 管理画面 - microCMS - nuxtmicrocms.microcms.io.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/165044/cc49e97a-a3a1-b667-b868-33224a37f850.png)

中身
![FireShot Capture 019 - 管理画面 - microCMS - nuxtmicrocms.microcms.io.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/165044/a94faf7d-3ebd-cbb1-214f-90ff9a49ff9d.png)

microCMSでの作業は以上です。簡単！

# Gridsome プロジェクト作成

これも[公式ドキュメント](https://gridsome.org/docs/)通りにすれば問題なく作成できるはず。

それと `dotenv` と `axios` を使用するのでついでにインストールしておきましょう。

`gridsome develop` でサーバーが起動できることを確認出来たら次に進みます。

# サーバー起動時にmicroCMSからデータを取得する

サーバーが起動したときの処理はgridsome.server.js  に記述します。

```js:gridsome.server.js
require('dotenv').config()
const axios = require('axios')

module.exports = function (api) {
  api.loadSource(async actions => {
    const { data } = await axios
      .get('https://yourapi.microcms.io/api/v1/news', {
        headers: { 'X-API-KEY': process.env.API_KEY }
      })

    const news = actions.addCollection({
      typeName: 'PostNews'
    })

    for (const item of data.contents) {
      news.addNode({
        id: item.id,
        title: item.title,
        body: item.body
      })
    }
  })
}
```

ここでコレクションを準備すると、他のファイルでも参照できるようになるみたいですね。

詳細はこちら => [Collections - 公式ドキュメント](https://gridsome.org/docs/collections/)

.env ファイルも準備

```:.env
API_KEY=xxxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxx
```

# GraphQLに変換し一覧表示

この辺はよくわかってないですが、とりあえずここでGraphQLに変換してるみたいです。

```vue:Index.vue
<template>
  <Layout>
    <ul>
      <li v-for="edge in $page.news.edges" :key="edge.node.id">
        <h2></h2>
        <g-link :to="'/news/' + edge.node.id">
          {{ edge.node.title }}
        </g-link>
      </li>
    </ul>

  </Layout>
</template>

<page-query>
query {
  news: allPostNews {
    edges {
      node {
        id
        title
        body
      }
    }
  }
}
</page-query>
```

# きちんと表示されればOK!

こんな感じに表示されるはず、です。

![FireShot Capture 020 - Hello, world! - Gridsome - localhost.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/165044/a10aac82-11e9-53a3-dfa4-6e22a100ae03.png)

今はまだリンク先を準備していないので遷移してもエラーになりますが、ひとまず表示は問題なさそうですね。

# 参考ページ

- [Collections - 公式ドキュメント](https://gridsome.org/docs/collections/)
- [Importing data - 公式ドキュメント](https://gridsome.org/docs/fetching-data/)
- [MicroCMSで取得したデータをGridSomeのGraphQLへインポートして表示する](https://codehack.dev/works/how-to-import-graphql-from-microcms-in-post/)

# ※追記 詳細画面の実装

```js:gridsome.config.js
module.exports = {
  siteName: 'Gridsome',
  templates: {
    PostNews: [
      {
        path: '/news/:id',
        component: './src/templates/PostNews.vue'
      }
    ]
  },
  plugins: []
}
```

```html:/src/templates/PostNews.vue
<template>
  <Layout>
    <h1>{{ $page.news.title }}</h1>
    <main>
      <div v-html="$page.news.body"></div>
    </main>
  </Layout>
</template>

<page-query>
  query news($id: ID!) {
    news: postNews(id: $id) {
      title
      body
    }
  }
</page-query>
```

# ※追記 静的化しないページの実装

ドキュメントどおり、基本的にはnuxtと同じように実装するみたい
https://gridsome.org/docs/dynamic-routing/

```js:gridsome.server.js
module.exports = function (api) {
  api.createPages(({ createPage }) => {
    createPage({
      path: '/news/:id',
      component: './src/templates/News.vue'
    })
  })
}
```

```vue:/src/templates/News.vue
<template>
  <Layout>
    <h1>{{ news.title }}</h1>
    <div v-html="news.body" />
  </Layout>
</template>

<script>
const axios = require('axios')
export default {
  data () {
    return {
      news: {}
    }
  },
  mounted () {
    axios.get(`https://yourapi.microcms.io/api/v1/news/${this.$route.params.id}`, {
      headers: {
        'X-API-KEY': 'xxx'
      }
    }).then((res) => {
      this.news = res.data
    }).catch((err) => {
      console.log(err)
    })
  }
}
</script>
```