用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,将会显示出如下画面。
在左侧窗格中输入并执行以下查询,将返回存储在链接表中的数据。
{
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