GraphCMS から入り、Absintheを利用して作って動かす「チュートリアル」

この記事は、「Elixir Advent Calendar 2019」の24日目になります。

「Elixir Advent Calendar 2019」23日目は、@sanpo_shihoさんの[Elixirで作るニューラルネットワークを用いた手書き数字認識①](https://qiita.com/sanpo_shiho/items/457c02a0007406dc381d)でした。

そしてこの記事は、「fukuoka.ex Elixir／Phoenix Advent Calendar 2019」の1日目から始まった３部作の３つ目の記事で、Advent Calendar NervesJP 6日目の続きになります。

東京だけど fukuoka.ex の YOSUKENAKAO.me です。

普段は合同会社The Waggleで「教育」に関わるサービス作りのお仕事と学習教材の開発や
研修講座の企画開発をしています。

この記事の構成
Advent Calendar fukuoka.ex 1日目
https://qiita.com/advent-calendar/2019/fukuokaex
[GraphCMS から Absinthe を利用して作る Elixir で体験的に GraphQLSever を作る「ポエム」](https://qiita.com/Yoosuke/items/2346137ac39715b19cde)

Advent Calendar NervesJP 6日目
https://qiita.com/advent-calendar/2019/nervesjp
Nerves と GraphQLsever の組み合わせを考える「ポエム」

Advent Calendar Elixir 24日目
https://qiita.com/advent-calendar/2019/elixir
GraphCMS から入り、Absintheを利用して作って動かす「チュートリアル」

となっています。

# 対象者はプログラミングを始めたい人で、新しい技術を学びたい人
逆を言えば、このチュートリアルができない人で、プログラミングを学びたい人は
Elixir |> Collegeの対象者です。

また、このチュートリアルは完了して、日本語で学びたい人は TheWaggleのオンライン教材の対象者（2020年春頃ローンチに向けて作成中）です。

## 注意点
このチュートリアルは、最短で何を学ぶべきかと、流れを通してそれぞれの技術的な繋がりを把握してもらう為のものです。

独学ができる人に向けた最初の入り口です。
PHP？ Python? Ruby? がやりたいだって？やりたい勉強すりゃいいよ。ただし一言だけ言っておく、Elixirは良いぞ（笑）

* HTML,CSS,JavaScript
* React
* GraphCMS
* Elixir
* Phoenix
* Ecto
* GraphQL（Queryのみ)
* Apollo
* Absinthe
* SQL
* mix

## チュートリアルの流れ

1. GraphCMSのアカウント登録
2. GraphCMSでModelの作成
2. Reactの環境構築（Yarnが使える人は飛ばす）
3. サンプルプログラムのダウンロードと作成
5. サンプルデータの作成
7. GraphCMS Endpointの設定
8. ElixirでGraphQL Server構築

# 1.GraphCMSのアカウント登録

下記のサイトへアクセスしてください。
https://graphcms.com/

<img width="720" alt="330af3a7-3a8c-52e5-1b79-e6fcb62fcfcd.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72962/23bd8215-432e-ef34-3abd-10b0c7df5622.png">

1. SignUpよりユーザー登録をします。
2. その後、ログインして下さい。
3. Login後、「Create new project」をクリックします。
<img width="720" alt="ae4f442c-2688-af08-0376-f60b318c919e.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72962/094d33c7-8ccf-0aaa-bdde-d1d6d85ba332.png">

4. 「Form Scrach」を選択します。

<img width="720" alt="bdd26e33-0720-7b54-77a6-f598b079e763.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72962/79c52368-bab1-1de2-5adf-5f65b5861dab.png">

５. 「Asia East」のリージョンを選びます。

<img width="720" alt="f7a63dbe-f92b-c924-2d71-4d8b5c8938e9.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72962/6cf37547-695f-2935-a493-389fbb51e131.png">

６. Pearsonalプランを選択し、Continueを選びます。

<img width="720" alt="9536e393-68dc-62a2-e802-5a82154136f0.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72962/dc73ba86-554c-ae5e-ec91-f761ae769e08.png">

７. モデルの作成から順に行って行きます。 

<img width="720" alt="f109de0f-aeae-aa14-37ac-8d633a176c7f.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72962/c9c8761d-e94e-1511-e707-cfabe6cc2938.png">

## 2. GraphCMSでModelの作成

８. Schemaの設定

Schemaと書かれたタイトルの下にModelsと書かれていてサイドに[＋]のボタンがあります。

<img width="720" alt="743a34b0-4370-1bb9-150b-43d4d9820eb0-1.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72962/247d230f-7bca-ddb0-657e-4592c68aed04.png">

９. Create Modelで「Display Name」の欄にAuthorと入力し、Create Modelを押します。

<img width="720" alt="0e2b3e5b-5235-cd3f-2968-0b4c4211518c.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72962/8189f595-2899-cbf2-5a0a-8b040a81163d.png">

１０. 右側にFIELDSと書かれたタブが表示されるので、クリックします。

<img width="720" alt="c781f204-fc61-5ae0-fa5a-19a6bb89127b.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72962/15a82b43-ae6f-a136-eeda-20a2b6d9ba98.png">

１１. 様々なFiledsのタイプがあります。今回は、Single Textをドラッグしてドロップします。

<img width="720" alt="9423fd1c-d442-ae67-c120-ffd0e32319c2.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72962/646efdd9-b0bb-112d-ed98-29d08222e446.png">

１２. Display Nameに　nameと入力します。

<img width="720" alt="88bbaeed-7744-3e01-3e32-9d5bd197eb52.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72962/3961202b-0432-1232-73a8-812011a05e0b.png">

１３. フィールドタイプが追加されるとこのような形になります。

<img width="720" alt="b855a074-78fc-af15-7912-7861cda50ee8.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72962/318f761d-dcf9-50fe-848b-b799b92099d1.png">

同じ要領で、Authorのフィールドは以下のように設定します。

<img width="1356" alt="スクリーンショット 2019-12-23 20.15.57.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72962/f10c4979-2248-4533-22d7-59a20e1fc9c6.png">

１４. Authorを設定したら新しく、ModelをPostで作成します。フィールドは以下のようにします。
<img width="1360" alt="スクリーンショット 2019-12-23 20.16.37.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72962/dddc57b9-f18d-37aa-feae-547f5fb4b2e8.png">



## 3.Reactの環境構築（Yarnが使える人は飛ばす）
### NodeJSのインストール
https://nodejs.org/ja/

LTS版と最新版があります。 LTS版をインストール

### インストールの確認

コンソールを再起動します。

```
node --version
```
次の```v12.13.1```ようにバージョン番号が表示されていたらインストール完了です。

```
npm --version
```

次の```v6.12.1```ようにバージョン番号が表示されていたら成功です。

## Yarn install
https://yarnpkg.com/ja/docs/install#mac-stable

Windowsの場合は、yarn のインストーラーをダウンロードできるボタンが表示されるので
それをダウンロードしてインストールして下さい。



## 4. サンプルプログラムのダウンロードと作成
https://github.com/GraphCMS/graphcms-examples/tree/master/current/react-apollo-blog

上記のサイトに下記コマンドを実行と記載があるので、下記のコマンドを実行します。

```
git clone https://github.com/GraphCMS/graphcms-examples.git && cd graphcms-examples/current/react-apollo-blog && yarn && yarn start
```

実行すると、ブラウザでlocalhost:3000で以下のサイトが見れたら成功です。

![blog_.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72962/572bb0b2-3e05-6d32-486e-2e2c169b4f14.png)

## 5. サンプルデータの作成

1. 「content」ボタン（三本の横棒マーク）をクリックし、データを入力したい、「Model名」（画像の例は、Author）を選びます。
2. 「Create New」をクリックすると、入力フィールドが表示されるので、適当な値を入れて「Published」を選んで「Save」します。

<b> ※Postにも忘れずに、同じ要領でサンプルデータを作成してください。</b>

<img width="990" alt="sample_data_set.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72962/e91dad1a-eef0-1b38-33e4-de09e0cb90ef.png">

## 6. GraphCMS Endpointの設定

設定から、Endpointをコピーします。

<img width="720" alt="68747470733a2f2f71696974612d696d6167652d73746f72652e73332e61702d6e6f727468656173742d312e616d617a6f6e6177732e636f6d2f302f37323936322f66343739643633622d663938342d363839382d323733302d3761666335353961633036362e706e67.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72962/a75b2fea-200b-c5ec-e79d-3b5f72285fc6.png">

Endpointをコピーしたら、設定より、PermissionsのScopeを「PROTECTED」から「QUERY」に変更します。

<img width="720" alt="68747470733a2f2f71696974612d696d6167652d73746f72652e73332e61702d6e6f727468656173742d312e616d617a6f6e6177732e636f6d2f302f37323936322f36613236663035302d326638342d643965322d653162302d3631366139633264393532342e706e67.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72962/71fc616e-832e-5aa2-06c7-db739bbfc288.png">

Endpointをプログラムに反映する

```react-apollo-blog/src/index.js
// Replace this with your project's endpoint
 const GRAPHCMS_API = 'ここに先ほどコピーしたEndpointのURLを入れる'
```
index.jsの全体像
<img width="983" alt="スクリーンショット 2019-12-24 10.12.43.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72962/9413e443-e4ee-bde4-7175-6974237d1e93.png">

ここまできたら　``` yarn start```で無事に自分の入力したデータが表示される事を確認します。

ここからは、こちらのブログで書いた手順の５番目以降の説明と同じものになります。
https://qiita.com/Yoosuke/items/2346137ac39715b19cde

6.　Absinthe を使用して GraphQL のアプリをセットアップします。

```elixir:mix.exs
defp deps do
 [
   # existing dependencies

   {:absinthe, "~> 1.4.16"},
   {:absinthe_plug, "~> 1.4.0"},
   {:absinthe_phoenix, "~> 1.4.0"}
 ]
end
```

```
mix deps.get
```

7.sampleBlog_web に schema フォルダを作成し、schema.ex ファイルを作成して、ファイルを作成します。

```elixir:lib/sampleBlog_web/schema/schema.ex
defmodule SampleBlogWeb.Schema.Schema do
    use Absinthe.Schema
  
    query do
      @desc "Get a list of authors"
      field :authors, list_of(:authors) do
        resolve &SampleBlogWeb.Resolvers.Blog.authors/3
      end
  
      @desc "Get a author by its id"
      field :author, :author do
        arg :id, non_null(:id)
        resolve &SampleBlogWeb.Resolvers.Blog.author/3
      end
    end
  
    object :author do
      field :id, non_null(:id)
      field :name, non_null(:string)
      field :bibliography, non_null(:string)
    end
  end
```

8.リゾルバモジュールファイルを作成します。 sampleBlog_web に resolvers フォルダを作成し、blog.exファイルを作成して、ファイルを作成します。

```elixir:lib/sampleBlog_web/resolvers/blog.ex
defmodule SampleBlog.Resolvers.Blog do
  alias Getaways.Blog

  def authors(_, _, _) do
    {:ok, Blog.list_authors()}
  end

  def author(_, %{id: id}, _) do
    {:ok, Blog.get_author!(id)}
  end
end
```

9.スキーマとリゾルバの準備をしたら、ルーターを設定します。

```elixir:sampleBlog/lib/sampleBlog_web/router.ex
defmodule SampleBlogWeb.Router do
defmodule SampleBlogWeb.Router do
  use SampleBlogWeb, :router

  pipeline :api do
    plug :accepts, ["json"]
  end

  scope "/" do
    pipe_through :api

    forward "/api", Absinthe.Plug,
      schema:  SampleBlogWeb.Schema.Schema

    forward "/graphiql", Absinthe.Plug.GraphiQL,
      schema:  SampleBlogWeb.Schema.Schema,
      interface: :simple
  end
end
```

最後にサーバーを起動してみます。

```
mix phx.server
```

これで```localhost:4000/graphiql```にアクセスして以下の画面が出てきたら作成準備完了です。

![キャプチャ.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72962/f50f059a-941a-0aa8-fda3-55dad2858b59.png)

## GraphQLのクエリを書く

```
query {
  authors{
    　id
　　　name
　　  bibliography
  }
}
```

クエリを書いて、無事に成功していれば下記のようなデータが返ってきます。

![graphql_1.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72962/d5047dfc-0961-c5f6-4e0b-9c5fd49b4299.png)


## React のreact-apollo-blog のAbout.jsに上記のクエリを上書きする

```src/components/About.js
export const authors = gql`
query authors {
  authors{
    id
    name
    bibliography
  }
}
`
```

エンドポイントを書き換える

```src/index.js
const GRAPHCMS_API = http://localhost:4000/api/
```

これで、```yarn start ```して```localhost:3000/about```ページにアクセスすると、、、見れません。
エラーを確認するとクロスサイトスクリプティングの問題でデータが取得できてないです。そこで、GraphQL server側に機能を追加します。

## Cros_plugを追加する

https://hex.pm/packages/cors_plug

```mix.exs

  defp deps do
    [
# ~省略
      {:absinthe, "~> 1.4.2"},
      {:absinthe_plug, "~> 1.4.0"},
      {:absinthe_phoenix, "~> 1.4.0"},
      {:cors_plug, "~> 2.0"},     #<- 追加
    ]
  end

```

機能を追加する。

```
$ mix deps.get
```

## router.exのパイプラインにプラグを追加

```lib/sampleBlog_web/router.ex

  pipeline :api do
    plug CORSPlug, origin: "http://localhost:3000" #<-追加
    plug :accepts, ["json"]
  end
```

これで、``` http://localhost:3000/about```にアクセスで以下のようにデータが取得できたら成功です。

![blog.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72962/ac4157aa-3158-f59d-1ce3-1f30a65ba633.png)

## 最後に
いかがだったでしょうか、あまりにも長いのでもしかしたら、抜け漏れがあるかもしれません。
見つけたら遠慮なく、おしらせ下さい。喜んで修正したいと思います。

よければ、いいね。よろしくお願いします。励みになります。