GraphCMSとHugoを連携してGithub Pagesで公開する(1)〜GraphCMSの設定 

# 概要

HugoとGraphCMSを組み合わせてコンテンツを生成していく。
そしてGithub Actionsで自動ビルドし、生成した静的ファイルをGithub Pages公開するのが最終目的である。

## Hugo

スタティックサイトジェネレータの[Hugo](https://gohugo.io/)を最近よく利用している。
Hugoの魅力は豊富なテーマや高速ビルドが挙げられる。
一方、特性上[Gatsby](https://www.gatsbyjs.com/)や[Nuxt.js](https://nuxtjs.org/)等ではよく利用されているヘッドレスCMSとの直接連携はできない。

## GraphCMS

ヘッドレスCMSの[GraphCMS](https://graphcms.com/)は[Contentful](https://www.contentful.com/)や[CosmicJS](https://www.cosmicjs.com/)等と比較して以下の優れた点がある。

* 無料区分枠で利用できるAPIコール数が多い。
* リッチコンテンツをhtmlでWYSIWYGエディタで書くことができる
* そしてなんといってもGraphQLが使える
* またレスポンスのjsonがシンプルな構造をしているので扱いやすい

逆にイケていないところは

* イケていると思ったWYSIWYGエディタがとても使いづらい(笑)
* RestfulAPIに慣れていてGraphQLってなんじゃらほいと思うと使いづらい(笑)
* Webhookのpayloadが自由にカスタマイズできないためGithubのAPIが利用できない。

などがある。上記Webhookの制限によりGraphCMS単体ではGithub Pagesで公開することはできない。
これらのデメリットが問題にならない場合は超絶オススメである。

> 利用条件については変更される場合があるので随時確認していただきたい。

# GraphCMSによるコンテンツ作成

まずサインアップだがGithubやGoogleアカウントがあればすぐに可能である。
完了すれば[GraphCMS](https://graphcms.com/)にログインする。
そして画面下部のほうにある`Create a new project`に移動。
いくつかテンプレートがあるが今回は`Blank`を用いてスクラッチで作成する。

`Name`はプロジェクト名、`Description`は説明、リージョンは特に理由がない限り`Asia(Tokyo)`を選ぶ。
入力したら`Create project`をクリック。

![FireShot Capture 003 - GraphCMS - app.graphcms.com.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/691494/52727f4b-ed20-6c3f-2ad2-300aac2481b0.png)

次にプランの選択画面。フリープランで使う場合は`Free forever`を選び`Select plan`を実行。

![FireShot Capture 004 - GraphCMS - app.graphcms.com.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/691494/1e1d9710-8efe-a4da-e5f7-9b74b38f84ea.png)

`Invite your team members`というメンバを招待する画面になるので特に不要であれば`Invite later`をクリック。

![FireShot Capture 005 - GraphCMS - app.graphcms.com.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/691494/b8d74085-7c6c-ddde-c96d-fe6dab30001d.png)

そうするとプロジェクトの管理画面が表示される。そして左側のメニューを選んで操作をする。

![FireShot Capture 007 - GraphCMS - app.graphcms.com.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/691494/cd7ffcbf-be94-d712-e50a-269e884cc748.png)

## スキーマ定義

まずはコンテンツのスキーマを定義してブログのコンテンツを設計する。  
メニューの`Schema`を選ぶ。
左側に`Models`、`Assets`、`Enumerations`が表示されているが基本は`Models`でモデル作成を行う。

![FireShot Capture 008 - GraphCMS - app.graphcms.com.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/691494/763893d6-8cf9-1443-ff67-70478d7c5834.png)

`Models`横の`Add`をクリックすると`Create Model`というフォーム画面が表示されるので`Display name`を適当に入力。
ここでは`post`とした。

![FireShot Capture 009 - GraphCMS - app.graphcms.com.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/691494/507566ec-d2ba-4be0-8a5c-6e2d2886bd1d.png)

すると`API ID`と`Plural API ID`が自動的に入力される(ここでは`Post`と`Posts`)。
この2つはGraphQLの呼び出し時に使い分ける。

* `Post (API ID)`: 単一のコンテンツを呼び出す場合、つまりID指定でコンテンツの詳細を取得する場合
* `Posts (Plural API ID)`: 複数のコンテンツを呼び出す場合、つまり一覧表示など複数のコンテンツを取得する場合

最初はこれを知らずにリストを取得する場合も`Post`を使ってしまいドハマりした。

すべて入力したら`Create Model`をクリック。
`Add Fields`というメニューが表示されるのでモデルのフィールドを追加していき設計する。
種類は以下の通り(縦長に表示されるので切り貼りした)

![FireShot Capture 011 - GraphCMS - app.graphcms.com.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/691494/0b8758ef-5340-28b6-9ea4-5385235b3071.png)

早速フィールド追加に取り掛かる。
まずはタイトル。`Single line text`をクリックするとダイアログが表示されるので以下のように入力する。

![FireShot Capture 019 - GraphCMS - app.graphcms.com.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/691494/e95040f1-c648-af05-252e-f223e404a5c1.png)

`VALIDATIONS`タブをクリックして属性を追加する。ここでは`Make field required`にチェックをした。

![FireShot Capture 020 - GraphCMS - app.graphcms.com.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/691494/f1ca67b0-5de5-c07d-101c-bf488e54a3a6.png)

その他のフィールドも追加し、以下のような構成になった。

![FireShot Capture 046 - GraphCMS - app.graphcms.com.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/691494/b9ab135e-62ae-5cca-b73b-8eeb4626969e.png)

* `title`: ブログのタイトル
* `slug`: スラグ。マルチバイト圏では使いづらいがURLがクリーンになるから採用
* `date`: 投稿日
    * `DateTime`型でやってもよいがそこまでそこまで細かい情報が不要だし、入力も面倒なので日付のみとした
* `eyecatch`: 投稿の看板画像
    * 今回の案件では投稿の一覧を画像で表示するため、必須項目としている
* `body`: ブログ本文
    * `RitchText`を使うとhtml形式でで書けるが、使いやすい`Markdown`採用
* `tag`: タグ

今回の案件では不要なので作っていないが、よくあるブログの構成としてはカテゴリーがある。
その場合、別途モデル定義して`Reference`で参照(いわゆるリレーショナル)するのが一般的かもしれない。
しかし、単純に文字列情報のみであるならば左メニューの`Models`で定義するよりは`Enumerations`で作成して`Dropdown`フィールドを使うほうが、クエリーがシンプルになる。
今回はタグもモデル定義せずに複数行入力できる`Single line text`で実装している。
Hugo側が勝手にタグの処理してくれるのでこれで十分である。

ちなみにこれらをモデルで定義したほうがよいのは、文字情報以外に属性を追加したい場合、例えばi18n(国際化)などがある。

また下書きはGraphCMS側で行っているのでフラグ管理はしていない。
コンテンツの作成・更新・公開などのタイムスタンプ情報はシステムフィールドで持っているので投稿日として使っても良い。
投稿者も私しかいないのでフィールド定義はしないが、これもシステムフィールドで持っているので表示できる。
これらの情報は`Show system fields`トグルをオンにすると見ることができる。

## コンテンツ作成

ここまでできたのでコンテンツの作成に取り掛かる。
ダッシュボード左メニューの`Content`をクリック。
`Create Item`をクリック。

![FireShot Capture 040 - GraphCMS - app.graphcms.com.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/691494/b9161ef0-bafe-f765-28b7-6d37376d0fdf.png)

そして適当に入力したのが下の様子(画像は[Lorem Picsum](https://picsum.photos/)より)。

![FireShot Capture 043 - GraphCMS - app.graphcms.com.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/691494/18486317-ac5d-c161-23e0-c93e3b2d5780.png)

ここで注意してほしいのは画像ファイル。`eyecatch`の箇所で表示されているようにアップロード時は`Draft`状態になる。
そのためコンテンツを`Published`状態にするだけでなく画像も同様に`Published`にする。

一旦、コンテンツを保存する。`Save`は下書き保存。`Save and publish`が公開。
取り敢えず`Save`で保存して左メニューの`Assets`をクリック。

![FireShot Capture 044 - GraphCMS - app.graphcms.com.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/691494/7e27c3a8-fee9-d2d6-c79a-7835803e0307.png)

チェックを入れて`Publish`ボタンをクリック。

![FireShot Capture 045 - GraphCMS - app.graphcms.com.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/691494/733ef057-6ff4-c442-3aaf-238b826c17c5.png)

`Published`状態になれば先程のコンテンツに戻り`Publish`をクリックして公開する。

![FireShot Capture 047 - GraphCMS - app.graphcms.com.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/691494/3fc3ff7b-83f0-8238-60dd-f26ab1199d10.png)

## GraphQLで作成したコンテンツの取得

先程投稿したコンテンツをGraphQLで取得してみる。
まず左メニュー`API Playground`をクリック。

![FireShot Capture 048 - GraphCMS - app.graphcms.com.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/691494/7426e4a0-ab20-a423-3183-3891d2a283b1.png)

ここで最初は途方にくれるが、まず`Explorer`タブをクリックし、先述した`Plural API ID`の名称、ここでは`posts`を選択する(`post`ではない)。
そして適当にフィールドをクリックしてこんな感じのクエリーを作成する。

```graphql
query MyQuery {
  posts {
    id
    title
    slug
    date
    eyecatch {
      url
    }
    body
    tag
  }
}
```

そして真ん中のプレイボタンをクリックして実行。

![FireShot Capture 050 - GraphCMS - app.graphcms.com.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/691494/31222165-796a-d954-6264-41e7c3bcdf66.png)

右側に結果がjson形式で返ってくるのがわかる。
これを素にHugoのコンテンツを作成するのだが次回はHugoの設定を解説する。