用Elixir的Absinthe库尝试了一下GraphQL

我试着用Elixir语言中的Absinthe库尝试了一下一直以来让我在意的GraphQL。根据我初步的调查,如果在Elixir中使用GraphQL,选择Absinthe应该是一个不错的选择。虽然它还处于测试阶段,但已经有相关的书籍出版了。
在这篇文章中,我将记录下我按照这里提供的教程做的事情,包括查询(query)和变更(mutation)。
代码示例在这里。

前提 tí)

安装了Erlang、Elixir和Phoenix。

样例应用的设置

我将使用Phoenix框架来创建基础应用程序。

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

将 absinthe 添加到 mix.exs 的 deps 中。

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

我会创建种子数据。

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!

将种子数据应用到数据库中。

$ mix ecto.setup

查询

首先,我们将定义 schema。将以下内容保存在 lib/graphql_sample_web/schema.ex 文件中。

虽然大致能看懂,但是 object :link do … 是定义了一个名为 link 的 object,而 query do … 则是定义了一个名为 allLinks 的查询。

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 模块需要另外进行定义,在 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 也能运行,但考虑到会变得更加复杂,通过引入这样的层面可能可以减低复杂度。可以将模块进行分离,使其更易于进行测试。

为了确认动作的设置

使用一个名为GraphiQL的浏览器库来验证GraphQL的功能。
通过将以下内容添加到router.ex文件中,/graphiql将成为GraphQL的有效终结点。

  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 の画面

在左侧窗格中输入并执行以下查询,将返回存储在链接表中的数据。

{
  allLinks {
    id
    url
    description
  }
}

突变

接下来我们将尝试进行数据操作的变异(Mutation)。

我将在lib/graphql_sample_web/schema.ex中添加以下内容。
“arg”是第一次出现,就如其名字一样代表参数。
这也挺符合外观的,我认为Absinthe干得不错。

  mutation do
    field :create_link, :link do
      arg :url, non_null(:string)
      arg :description, non_null(:string)

      resolve &NewsResolver.create_link/3
    end
  end

我们将在解析器的一侧添加以下内容。

  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
  }
}

通过将此提交到链接表,已将其添加到链接表中。可以通过再次查询 allLinks 来确认结果已增加。

摘要

因为能够感受到与 REST 的不同,所以暂时算是在入门阶段吧。
只是还没有能够试验取得客户端端所需内容或解决N+1问题等例子,所以还需要再努力一点来理解GraphQL。。。

资源

    • Building a GraphQL Server with Elixir Backend Tutorial https://www.howtographql.com/graphql-elixir/0-introduction/

graphql/graphiql: An in-browser IDE for exploring GraphQL. https://github.com/graphql/graphiql

Absinthe: Home http://absinthe-graphql.org/

Craft GraphQL APIs in Elixir with Absinthe: Flexible, Robust Services for Queries, Mutations, and Subscriptions by Bruce Williams and Ben Wilson | The Pragmatic Bookshelf https://pragprog.com/book/wwgraphql/craft-graphql-apis-in-elixir-with-absinthe

今回実際に試したコード https://github.com/ma2gedev/graphql_sample

广告
将在 10 秒后关闭
bannerAds