I'm attempting to receive a string of JSON in my graphql implementation but keep getting errors with the custom scalar I've defined to handle the JSON.
I've defined a custom scalar to properly serialize the JSON to an elixir map. I'm getting errors that I have invalid data types before my code reaches the parsing stage of the custom scalar. I'm attempting to use https://github.com/absinthe-graphql/absinthe/wiki/Scalar-Recipes#json-using-jason to create the scalar however I've modified to use Poison instead of Jason.
My absinthe mutator using the :json scalar type I created.
@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
My scalar definition and graphql schema definition
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.String{value: 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
when sending the following queries:
mutation updateUser{
updateUser(client_store: "{"key":"value"}"){
id
}
}
I receive a syntax error before: \"\\\":\\\"\"
mutation updateUser{
updateUser(client_store: "hello"){
id
}
}
I receive a "Argument \"client_store\" has invalid value \"hello\"
Sending the GraphQL query through a unit test via Phoenix.ConnTest
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)
The problem is with your mutation, you need to escape the quotes inside the string, like this:
mutation updateUser{
updateUser(client_store: "{\"key\": \"value\"}"){
id
}
}
Otherwise, the interpretation is that the second quote marks the end of the string, so you basically have the string "{"
followed by key":"value"}"
, which is syntatically invalid.
Note that when sending the mutation in an unit test, you are defining the mutation as a string already, so you need to further escape the quotes:
query = """
mutation updateUser{
updateUser(client_store: "{\\\"key\\\":\\\"value\\\"}"){
id
}
}
"""
This may be a little tricky to understand at first, but printing it makes it clearer:
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
}
}
So the last one works because when the string is evaluated, the result is the original mutation, which escapes the quotes.