Elixir × GraphQLシリーズ
~ Abshinthe と Abshinthe crient の 連携 ~
この記事は「Elixir Advent Calendar 2022」22日目の記事です
東京にいるけどfukuokaexのYOSUKEです。
このシリーズは3部作目です。
前回までは以下
-
今回は、今まで簡単に説明していた?(いや、ほとんど説明はしてない)GraphQL Serverのセットアップは完了しているので、GraphQLの説明と、その利用方法を少し解説していきます。
GraphQLとは
GraphQLとは、アプリケーション プログララミング インタフェース(API)の1つで、REST APIなどと違って、クエリを駆使して、1つのエンドポイントからデータを柔軟に利用したいものだけ取得する事ができる仕組みです。
詳しく知りたい方は、GraphQLの学習を参考にしてください。
今回の構成
-
よくある、GraphQLを利用した開発の構成として使われるのは、フロント側の実装を(React,VueなどのSPA)で開発し、バックエンド側をGraphQLサーバーとして開発し、1つのエンドポイントで繋いで利用する。というものだと思いますが、
-
今回は、フロント側を LiveView を利用して、 フロントとバックを両方 Elixirで作成する方法を試していきます。
-
LiveViewを活かしたいので、クエリだけでなく、ソケットを利用したステートフルな形を準備していきます。
クエリとミューテーションとは
GraphQL の操作はクエリとミューテーションです。これらを create (作成)、read (読み取り)、update (更新)、delete (削除) (CRUD) モデルに照らして考えると、クエリは read (読み取り) に相当します。その他すべて (create、update、delete) はミューテーションによって処理されます。
クエリまでは、シリーズ①、②で実装してきましたが、ミューテーションの実装はまだでしたので、まずはミューテーションを実装していきたいと思います。
GraphQL ミューテーションの実装
スキーマにミューテーションの追加
defmodule OpenDataQlWeb.Schema.Schema do
use Absinthe.Schema
# 省略 #
mutation do
field :create_place, :place do
arg :lat, non_null(:float)
arg :location, non_null(:string)
arg :lon, non_null(:float)
arg :name, non_null(:string)
arg :scale, non_null(:integer)
resolve &OpenDataQlWeb.Resolvers.Community.create_place/3
end
end
end
リゾルバの作成
defmodule OpenDataQlWeb.Resolvers.Community do
alias OpenDataQl.Community
# 省略 #
def create_place(_, params, _) do
case Community.create_place(params) do
{:error, _} -> {:error, "Could not create place"}
{:ok, _} = success -> success
end
end
早速試してみましょう。
Firefox のADD ON にある GraphQL Clientからミューテーションを実行してみます。
今回は、変数を使わず、直接値を入力してミューテーションを実行してみました。
mutation{
createPlace(name: "name5", lat: 123.4, lon: 234.5, location: "name", scale: 9){
name
lat
lon
location
scale
id
}
}
ちゃんと挿入されているか確認してみましょう。以下のクエリを実行して確認します。
{
places{
name
scale
location
lat
lon
id
}
}
以下のように先ほどmutationで挿入したデータがちゃんと取得できることが確認できました。
GraphQL サブスプリクションの実装
GraphQL サブスクリプションは、サーバー内のイベントでデータをクライアントにリアルタイムでプッシュする方法になります。
クライアントは、特定のデータを要求するサブスクリプションを送信します。イベントが発生すると、そのイベントに対して実行され、結果のデータがプッシュされます。
そこで、ソケットを利用します。以下のコマンドでソケットを準びします。
ソケットの追加
$ mix phx.gen.socket User
2つファイルが生成されます。また、以下2つのファイルに関連付けを追記します。
socket "/socket", OpenDataQlWeb.UserSocket,
websocket: true,
longpoll: false
import "./user_socket.js"
defmodule OpenDataQlWeb.UserSocket do
use Phoenix.Socket
use Absinthe.Phoenix.Socket, schema: OpenDataQlWeb.Schema.Schema #<- 追記
サブスクリプションの実装
Application 監視ツリーに追記
def start(_type, _args) do
children = [
# 省略 #
{Phoenix.PubSub, [name: OpenDataQl.PubSub, adapter: Phoenix.PubSub.PG2]},
{Absinthe.Subscription, OpenDataQlWeb.Endpoint}
]
EndpointにAbsinthe.Phoenix.Endpoint
を追加
defmodule OpenDataQlWeb.Endpoint do
use Phoenix.Endpoint, otp_app: :open_data_ql
use Absinthe.Phoenix.Endpoint #<-追加
GraphiQL プラグを使用している場合は、 routerでsocketオプションを指定します。
if Mix.env() == :dev do
forward "/graphiql", Absinthe.Plug.GraphiQL,
schema: OpenDataQlWeb.Schema.Schema,
interface: :simple,
socket: OpenDataQlWeb.UserSocket
end
これで準びは完了です。
いよいよ、サブスクリプションの中身を実装して確認していきたいのですが、長くなりそうなので、サブスクリプションの実装編はまた時間ある時に何回かに分けて続きを書こうと思います。
今年は、サクッと書くのがコンセプトなので、(大作しすぎると続かなくなるので、今年はサクッと継続を重視していこうかと)