如何在 Absinthe GraphQL 请求中接受 JSON
Posted
技术标签:
【中文标题】如何在 Absinthe GraphQL 请求中接受 JSON【英文标题】:How to accept JSON in Absinthe GraphQL requests 【发布时间】:2019-06-01 15:59:06 【问题描述】:我试图在我的 graphql 实现中接收 JSON 字符串,但我为处理 JSON 而定义的自定义标量不断出现错误。
我已经定义了一个自定义标量来正确地将 JSON 序列化为 elixir 映射。在我的代码到达自定义标量的解析阶段之前,我收到错误数据类型无效。我正在尝试使用 https://github.com/absinthe-graphql/absinthe/wiki/Scalar-Recipes#json-using-jason 创建标量,但我已修改为使用 Poison 而不是 Jason。
我使用我创建的 :json 标量类型的苦艾变体。
@desc "Update user"
field :update_user, type: :user do
arg(:email, :string)
arg(:password, :string)
arg(:first_name, :string)
arg(:last_name, :string)
arg(:age, :integer)
arg(:client_store, :json)
resolve(handle_errors(&Resolvers.User_Resolver.update_user/3))
end
我的标量定义和 graphql 模式定义
scalar :json, name: "Json" do
description("""
The `Json` scalar type represents arbitrary json string data, represented as UTF-8
character sequences. The Json type is most often used to represent a free-form
human-readable json string.
""")
serialize(&encode/1)
parse(&decode/1)
end
# @spec decode(Absinthe.Blueprint.Input.String.t) :: :ok, :string | :error
# @spec decode(Absinthe.Blueprint.Input.Null.t) :: :ok, nil
defp decode(%Absinthe.Blueprint.Input.Stringvalue: value) do
Logger.info "decoded input value:"
case Poison.decode(value) do
:ok, result -> :ok, result
_ -> :error
end
end
defp decode(%Absinthe.Blueprint.Input.Null) do
:ok, nil
end
defp decode(_) do
:error
end
defp encode(value), do: value
object :user do
field(:id, :id)
field(:email, :string)
field(:password, :string)
field(:first_name, :string)
field(:last_name, :string)
field(:age, :integer)
field(:client_store, :json)
end
发送以下查询时:
mutation updateUser
updateUser(client_store: ""key":"value"")
id
我收到了syntax error before: \"\\\":\\\"\"
mutation updateUser
updateUser(client_store: "hello")
id
我收到了"Argument \"client_store\" has invalid value \"hello\"
通过 Phoenix.ConnTest
的单元测试发送 GraphQL 查询
query = """
mutation updateUser
updateUser(client_store: "\"key\":\"value\"")
id
"""
res =
context.conn
|> put_req_header("content-type", "text")
|> put_req_header("authorization", token)
|> post("/api", query)
【问题讨论】:
【参考方案1】:问题在于您的突变,您需要转义字符串中的引号,如下所示:
mutation updateUser
updateUser(client_store: "\"key\": \"value\"")
id
否则,解释是第二个引号标记了字符串的结尾,所以你基本上有字符串""
后跟key":"value""
,这在语法上是无效的。
请注意,在单元测试中发送突变时,您已经将突变定义为字符串,因此您需要进一步转义引号:
query = """
mutation updateUser
updateUser(client_store: "\\\"key\\\":\\\"value\\\"")
id
"""
一开始可能有点难以理解,但打印出来会更清楚:
iex(1)> """
...(1)> mutation updateUser
...(1)> updateUser(client_store: "\"key\":\"value\"")
...(1)> id
...(1)>
...(1)>
...(1)> """ |> IO.puts()
mutation updateUser
updateUser(client_store: ""key":"value"")
id
iex(2)> """
...(2)> mutation updateUser
...(2)> updateUser(client_store: "\\\"key\\\":\\\"value\\\"")
...(2)> id
...(2)>
...(2)>
...(2)> """ |> IO.puts()
mutation updateUser
updateUser(client_store: "\"key\":\"value\"")
id
所以最后一个有效,因为在评估字符串时,结果是原始突变,它转义了引号。
【讨论】:
不幸的是,运行mutation updateUser updateUser(client_store: "\"key\": \"value\"") id
产生:syntax error before: \"\\\": \\\"\"
。
你是如何发送突变的?通过 GraphiQL?
在单元测试中通过Phoenix.ConnTest
发送。我将包括我发送问题的方式以提高知名度。
好的,我已经通过 GraphiQL 让它工作了。不确定单元测试有什么问题。完成后我会发布。感谢您的帮助。
我已经编辑了我的答案以解决您在单元测试中遇到的问题。【参考方案2】:
我是这样测试的
test "should get an existing key" do
:ok, user = Api.Auth.Users.create_user(%name: "Test User")
:ok, app = Api.Auth.Apps.create_app(%owner_id: %type: :user, id: user.id, name: "name")
:ok, key = Api.Auth.Keys.create_key(%app_id: app.id)
%resp_body: response =
build_conn()
|> post("graphql", %
"query" => """
query
key(id: "#key.id")
id
"""
)
%"data" => %"key" => %"id" => id = Jason.decode!(response)
assert key.id == id
end
end
【讨论】:
以上是关于如何在 Absinthe GraphQL 请求中接受 JSON的主要内容,如果未能解决你的问题,请参考以下文章
Elixir Absinthe GraphQL,联合 resolve_type list_of/1
如何在所有 GraphQL 请求的标头中注入 Id。例如,在所有 GraphQL 请求的标头中,它应该像:- Id:1234