Elixir × GraphQL系列 ③ 添加Mutation和Subscription设置
金丹 × GraphQL系列
– Absinthe 和 Absinthe crient 的合作
这篇文章是「Elixir Advent Calendar 2022」的第22篇文章。
虽然我在东京,但我是fukuokaex的YOSUKE。
这个系列是第三部作品。
之前的部分如下。
Elixir × GraphQLシリーズ① ~ サクッとGraphQLサーバーのセットアップ ~
Elixir × GraphQLシリーズ ② ~ サクッと Abshinthe-crient Setup ~
今回は、今まで簡単に説明していた?(いや、ほとんど説明はしてない)GraphQL Serverのセットアップは完了しているので、GraphQLの説明と、その利用方法を少し解説していきます。
GraphQL是一种查询语言。
GraphQL是一种应用程序编程接口(API)之一,与REST API等不同,它通过查询来灵活地获取想要的数据,只需从一个端点获取。
如果您想更详细地了解,请参考GraphQL的学习资源。
这次的结构
よくある、GraphQLを利用した開発の構成として使われるのは、フロント側の実装を(React,VueなどのSPA)で開発し、バックエンド側をGraphQLサーバーとして開発し、1つのエンドポイントで繋いで利用する。というものだと思いますが、
今回は、フロント側を LiveView を利用して、 フロントとバックを両方 Elixirで作成する方法を試していきます。
LiveViewを活かしたいので、クエリだけでなく、ソケットを利用したステートフルな形を準備していきます。
查询和变更指什么?
GraphQL操作主要包括查询和突变两种类型。根据CRUD模型,可以将它们对应到创建、读取、更新和删除。查询代表读取操作,而其余三种操作(创建、更新、删除)则通过突变来进行处理。
我們已經在系列1和系列2中實現了查詢部分,但尚未實現變異部分,因此我們首先希望實現變異部分。
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客户端执行一个mutation。

这次我尝试了不使用变量,直接输入数值来执行突变。
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
}
}
我已经确认我们可以正确获取到刚刚通过变异插入的数据。

GraphQL 订阅的实现
GraphQL 订阅是一种在服务器内部事件中实时向客户端推送数据的方法。
客户端发送订阅以请求特定数据。当事件发生时,执行相应的操作并推送结果数据。
那么,我们可以使用套接字。使用以下命令来准备套接字。
增加插孔
$ mix phx.gen.socket User
将生成两个文件。此外,还将在以下两个文件中添加关联。
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 #<- 追記
订阅的实施方式
在申請监视树中追加。
def start(_type, _args) do
children = [
# 省略 #
{Phoenix.PubSub, [name: OpenDataQl.PubSub, adapter: Phoenix.PubSub.PG2]},
{Absinthe.Subscription, OpenDataQlWeb.Endpoint}
]
在Chinese中,只需要一个选项来释义以下内容:
将Absinthe.Phoenix.Endpoint添加到Endpoing中。
defmodule OpenDataQlWeb.Endpoint do
use Phoenix.Endpoint, otp_app: :open_data_ql
use Absinthe.Phoenix.Endpoint #<-追加
如果您正在使用GraphiQL插件,则需要在路由器上指定socket选项。
if Mix.env() == :dev do
forward "/graphiql", Absinthe.Plug.GraphiQL,
schema: OpenDataQlWeb.Schema.Schema,
interface: :simple,
socket: OpenDataQlWeb.UserSocket
end
这样一来,准备工作就完成了。
终于,我想要实现和确认订阅内容,但由于可能会变得很长,所以我打算将订阅实现部分分成几个时段,再继续写下去。
由于今年的概念是快速写作,所以我打算强调持续性,不太想写太多(如果写得太繁杂,可能无法坚持下去,所以我打算今年注重持续性,轻松写作)。