Help us understand the problem. What is going on with this article?

Elixir で Absinthe を使って GraphQL に触れてみた

More than 1 year has passed since last update.

前々から気になっていた GraphQL を Elixir 言語で作られたライブラリの Absinthe を使って試してみました。軽く調べた感じでは Elixir で GraphQL するなら Absinthe 選ぶで良さそうです。まだベータですが本も出ています
この記事ではこちらにあるチュートリアルを元に query と mutation に触れるところまでやったことをメモします。
サンプルコードはこちら

前提

Erlang & Elixir & Phoenix あたりはインストールされている。

サンプルアプリのセットアップ

Phoenix Framework を使って土台となるアプリを作ります。

$ mix phx.new graphql_sample --no-brunch --no-html
$ cd graphql_sample

mix.exs の deps へ absinthe を追加します。

mix.exs
def deps do
  ...省略...
  {:absinthe_ecto, "~> 0.1.0"},
  {:absinthe_plug, "~> 1.3.0"}
end

absinthe を追加したのでライブラリを取得して DB まで作ります。

$ mix deps.get
$ mix ecto.create

データモデルのセットアップ

GraphQL でクエリをかけたり、データ操作をするためにモデルをセットアップします。
シンプルに links というテーブルを作るだけです。

$ mix phx.gen.context News Link links url:string description:text

seed 用のデータを作ります。

priv/repo/seeds.ex
alias GraphqlSample.News.Link
alias GraphqlSample.Repo

%Link{url: "http://graphql.org/", description: "The Best Query Language"} |> Repo.insert!
%Link{url: "http://dev.apollodata.com/", description: "Awesome GraphQL Client"} |> Repo.insert!

seed データを DB へ反映します。

$ mix ecto.setup

Query

まずは schema を定義します。lib/graphql_sample_web/schema.ex として以下内容を記載します。
見てなんとなく分かりますが、object :link do ... で link という object を定義、query do ...allLinks クエリを定義しています。

lib/graphql_sample_web/schema.ex
defmodule GraphqlSampleWeb.Schema do
  use Absinthe.Schema

  alias GraphqlSampleWeb.NewsResolver

  object :link do
    field :id, non_null(:id)
    field :url, non_null(:string)
    field :description, non_null(:string)
  end

  query do
    field :all_links, non_null(list_of(non_null(:link))) do
      resolve &NewsResolver.all_links/3
    end
  end
end

Absinthe が all_links を GraphQL 用に allLinks に変換してくれるようです。

GraphqlSampleWeb.NewsResolver module は別途定義が必要で、以下のように lib/graphql_sample_web/resolvers/news_resolvers.ex へ定義します。

lib/graphql_sample_web/resolvers/news_resolvers.ex
defmodule GraphqlSampleWeb.NewsResolver do
  alias GraphqlSample.News

  def all_links(_root, _args, _info) do
    links = News.list_links()
    {:ok, links}
  end
end

このレベルであれば Resolver なくてもという感じですが、複雑になってくることを考えるとこういった層を挟むことで複雑度を抑えられるのかなという感触。module 分けたり、よりテスタブルになったりね。

動作確認のための設定

GraphiQL というブラウザで動くライブラリを使って GraphQL の動作を確認します。
以下のように router.ex へ追加することで /graphiql が GraphQL 用のエンドポイントとして有効になるようです。

lib/graphql_sample_web/router.ex
  scope "/" do
    pipe_through :api

    forward "/graphiql", Absinthe.Plug.GraphiQL,
      schema: GraphqlSampleWeb.Schema,
      interface: :simple,
      context: %{pubsub: GraphqlSampleWeb.Endpoint}
  end

$ iex -S mix phx.server でアプリを立ち上げ localhost:4000/graphiql へアクセスすると、こんな画面が表示されます。

GraphiQL の画面

左側のペインに以下クエリを入力して実行すると、link table に格納されているデータが返ってきます。

{
  allLinks {
    id
    url
    description
  }
}

Mutation

次にデータ操作のための Mutation を試します。

lib/graphql_sample_web/schema.ex へ以下を追加します。
arg というのが初めて出てきていますが、これはその名の通り引数です。
これも結構見た目通りなので、Absinthe 頑張ってくれているなと思います。

lib/graphql_sample_web/schema.ex
  mutation do
    field :create_link, :link do
      arg :url, non_null(:string)
      arg :description, non_null(:string)

      resolve &NewsResolver.create_link/3
    end
  end

Resolver 側には以下を追加します。

lib/graphql_sample_web/resolvers/news_resolvers.ex
  def create_link(_root, args, _info) do
    case News.create_link(args) do
      {:ok, link} ->
        {:ok, link}
      _error ->
        {:error, "could not create link"}
    end
  end

ここまで出来たらアプリを立ち上げてクエリ同様に localhost:4000/graphiql へアクセスします。

今度は左のペインへ以下のように入力して実行します。

mutation {
  createLink(
    url: "https://github.com/ma2gedev/power_assert_ex",
    description: "Power Assert Elixir",
  ) {
    id
    url
    description
  }
}

これで link table へ追加されました。再度クエリで allLinks を叩くことで結果が増えていることが確認できます。

まとめ

REST との違いを感じることができたので、とりあえず入り口くらいには立てたかなと。
ただ client 側で必要なものだけを取るとか、N+1 を解消させる例とか試したいところが全然試せていない感じなので、GraphQL を理解するにはもう少し頑張らねば。。。

Resources

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした