LiveViewをクライアントにしてGraphQLによる連携を実装する

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

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

現在、企業研修講師を募集しています。また、これから講師もキャリアとしてデビューしたい方も育成プランがありますので興味ある方はご連絡ください。

また、ARグラスのアプリ開発も行っていますので、Unityを使ってAR開発に興味ある方も募集してます。

## 記事構成
この記事は関連記事と併せて4部作で考えています。

1. GraphCMSを利用してヘッドレスCMSを構築しPhoenix LiveViewでGraphQL-Crientを実装しよう。ここではNuronを使った簡単なGraphQL-Crientの実装を試します。ちなみにGraphCMSの使い方については、要望多ければ別途記事にしますので、是非知りたい方はこちらの記事にアクションください。また、このチュートリアルではGraphCMSを利用しましたが、GraphQL Server機能を持っていれば何でも構いません。（本記事）

2. GraphQL ServerをPhoenixで構築しよう！（前編） Elixirアドベントカレンダー 12/8 投稿予定

3. GraphQL ServerをPhoenixで構築しよう！（後編） Elixirアドベントカレンダー 12/15 投稿予定

4. GraphQL Crientの変更Subscriptionsを実装しよう。 1で作成したGraphQLクライアントは、Subscriptionsがサポートされてない為、せっかくLiveViewを実装したのに、その恩恵があまり受けられないものとなってました。そこで、このシリーズの第４段では、その課題を解決する実装を模索したいと思います。　　Elixirアドベントカレンダー 12/22 投稿予定

## LiveViewをクライアントにしたGraphQLによる連携実装の概要
このチュートリアルは、以前書いたこちらの記事のリニューアル版です。が、当時はReactをフロントにバックエンドとしてGraphQLサーバーをPhoenixフレームワークを使って構築する方法をあげていました。しかし、最近ではLiveViewが充実してきたこともあり、クライアント側をLiveView（Phoenix）バックエンド側をGraphQL（Phoenix）の構成にしたものにします。

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

下記のサイトへアクセスしてください。
アカウントを作成してください。特に難しい事しないので割愛します。
https://graphcms.com/

### DEMO版のBlogを選びます。

アカウントを作成してログインした後、Add a new projectより 真ん中の サンプル Blog を選択します。
PS. Phoenixを学んで、何作ろうかな？DBの設計とか知らんしな。って方はこのサンプルでどのようにDB設計されてるか見れるのでおすすめです。

![スクリーンショット 2022-10-20 8.09.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72962/31ad4db8-75eb-faed-2a90-ebfefcd90604.png)

### リージョンを選択

ProjectのDetailsは特に変更しなくて大丈夫ですが、Regionについては、Japan（Tokyo）を選択してください。

![スクリーンショット 2022-10-20 8.10.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72962/44e298d9-ec12-1663-d35d-5be0e0aaffe1.png)

### 完成まで待つ

作成までしばらく時間がかかるので、のんびり待ちます。完了すると下記のような画面が見れます。

![スクリーンショット 2022-10-20 8.39.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72962/132a783a-dbeb-c33b-054e-cd319a29e4ba.png)

ここまで準備できたら、一旦LiveViewのフロント側を準備していきます。

## 2.　LiveViewのフロント実装

まずは、DBが不要なので、 --no-ecto オプションをつけて LiveViewのプロジェクトを生成します。今回はfetchという名前で作成してみました。

```bash
mix phx.new fetch --no-ecto --live
```

Graphql クライアントのインストールをします。
今回はシンプルに使いやすそうなGraphQL Crientの機能を追加できる neuron　を使用します。 

```elixir:mix.exs
defp deps do
 [
   # existing dependencies
    {:neuron, "~> 5.0.0"}
 ]
end
```

```
mix deps.get
```
以下の依存関係が追加されます。
```bash
New:
  certifi 2.9.0
  hackney 1.18.1
  httpoison 1.8.2
  idna 6.1.1
  metrics 1.0.1
  mimerl 1.2.0
  neuron 5.0.0
  parse_trans 3.3.1
  ssl_verify_fun 1.1.6
  unicode_util_compat 0.7.0
```

## GraphCMSとの接続

Neuronを使ってGraphCMSと接続してみましょう。
まずは、GraphCMSのエンドポイントとトークンをコピーし、それぞれ環境変数にセットしておきます。

### Endpointの設定

![スクリーンショット 2022-11-05 12.21.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72962/317a816d-e3e1-4813-3153-7a0aed5a7e15.png)

Content APIをコピーして、環境変数にセットしておきます。

```bash

export EX_GRAPHCMS_ENDPOINT="Content API（Endpoint）"

```


### Tokenの設定
![スクリーンショット 2022-11-05 12.23.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72962/2abb500c-1034-0619-486d-a768e3f14e9d.png)

```bash
export EX_GRAPHCMS_TOKEN="HYGRAPH_TOKENのValueをコピーした値"
```

それぞれ、環境変数に設定したら、Neuronのコンフィグに設定します。

```elixir
iex> Neuron.Config.set(url: System.get_env("EX_GRAPHCMS_ENDPOINT"))
:ok
iex> Neuron.Config.set(headers: ["Authorization": System.get_env("EX_GRAPHCMS_TOKEN")])
:ok
```

これで、GraphQLを取得する為の準びが完了したので、早速試して行きたいと思います。

### GraphQLでクエリを叩いてみる

```elixir
Neuron.query("""
{
# ここにgraphQL のクエリを書く
}
""")
```

成功すると、```status_code: 200``` と共に、```"data" =>```以下にデータを取得する事ができます。

```elixir
iex(4)>  Neuron.query("""
...(4)>     {
...(4)>       posts{
...(4)>         title
...(4)>         slug
...(4)>         id
...(4)>       }
...(4)>     }
...(4)>     """)
{:ok,
 %Neuron.Response{
   body: %{
     "data" => %{
       "posts" => [
         %{
           "id" => "ホニャララ",
           "slug" => "ホニャララスラグ",
           "title" => "Technical SEO with Hygraph"
         },
# ~ 省略 ~ 
   headers: [
     {"Date", "Sat, 05 Nov 2022 04:40:01 GMT"},
     {"Content-Type", "application/json"},
     {"Transfer-Encoding", "chunked"},
     {"Connection", "keep-alive"},
     {"Server", "cloudflare"}
# ~ 省略 ~ 
   ],
   status_code: 200
 }}
```

とりあえず、これでNeronを利用してGraphCMSからGraphQLを利用してデータを取得する事ができたので、早速LiveViewに反映させて行きたいと思います。

## 

```lib/fetch/blog.ex
defmodule Fetch.Blog do
  def get_blogs() do
    Neuron.query("""
    {
      posts{
        title
        slug
        id
      }
    }
    """)
  end
end

```

LiveViewでデータを取得して表示する処理を記載します。

```lib/fetch_web/live/blogs_live.ex
defmodule FetchWeb.BlogsLive do
  use FetchWeb, :live_view
  alias Fetch.Blog
  def mount(_params, _session, socket) do
    {:ok, blogs} = Blog.get_blogs()
    blogs = get_in(blogs.body["data"], ["posts"])
    socket = assign(socket, blogs: blogs)
    {:ok, socket}
  end

  def render(assigns) do
    ~L"""
    <%= for blog <- @blogs do %>
      Title: <%= blog["title"] %> </br>
      slug:  <%= blog["slug"] %></br>
      id:  <%= blog["id"] %>
      <hr>
    <% end %>
    """
  end
end
```

routerにliveViewへのルートを追記

```lib/fetch_web/router.ex
# ~ 省略 ~
 scope "/", FetchWeb do
    pipe_through :browser

    live "/blogs", BlogsLive #<- こちらを追記
  end
```

これで完成！と言いたい所ですが、このままだと、Neuron.configの設定を反映する箇所が抜けています。そこで、最後にアプリケーションファイルにNeuronのコンフィグ設定を追記します。

```lib/fetch/apprication.ex
defmodule Fetch.Application do
  @moduledoc false
  use Application

  @impl true
  def start(_type, _args) do
    children = [
        # ~　省略　~
    ]

        # ~　省略　~

    Neuron.Config.set(url: System.get_env("EX_GRAPHCMS_ENDPOINT")) #<- こちらを追記
    Neuron.Config.set(headers: ["Authorization": System.get_env("EX_GRAPHCMS_TOKEN")]) #<- こちらを追記

    Supervisor.start_link(children, opts)
  end
        # ~　省略　~
end
```
最後にちゃんと取得できてるか確認しましょう。

```elixir
mix phx.server
```

無事に取得できてるようですね。

![スクリーンショット 2022-11-05 14.56.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72962/4bb733b3-3ad2-fa06-a4ed-c4fbe4606906.png)


## 最後に
いかがだったでしょうか、本当は、この後 WebSocketを使って、データ書き換えを即時反映させたいと思ったのですが、Neuronのライブラリでは、GraphQLのSubscriptionsがサポートされておらず、Issueに上がってるものの、時間なくていつ取り込まれるかわかりません！とコメントされていたので、この後の続くシリーズにて、最終的には別のライブラリに変更して対応したいと考えてます。

という事で、Elixir Advent Calendar 2022 で続きを書いて行きたいと思います！
よければ、いいね。よろしくお願いします。励みになります。