-
Notifications
You must be signed in to change notification settings - Fork 90
Description
If submitting a bug, please provide the following:
Environment
-
Elixir version (elixir -v):
elixir 1.10.2
erlang 22.3.4.1 -
Absinthe version (mix deps | grep absinthe):
absinthe (Hex package) (mix) locked at 1.5.2 (absinthe) 669c8487
absinthe_relay (Hex package) (mix) locked at 1.5.0 (absinthe_relay) 173cc44c
absinthe_sorting_codec 1.0.0 (Hex package) (mix) locked at 1.0.0 (absinthe_sorting_codec) e5dd8152
absinthe_sdl 1.1.0 (Hex package) (mix) locked at 1.1.0 (absinthe_sdl) 8b5f6293
absinthe_plug (Hex package) (mix) locked at 1.5.0 (absinthe_plug) 4c160f4c
absinthe_phoenix (Hex package) (mix) locked at 1.5.0 (absinthe_phoenix) bbe443e8 -
Client Framework and version (Relay, Apollo, etc):
None, this is failing from unit tests
Expected behavior
In the ParseIDs middleware, there is a function find_schema_root!/2. I have several inspects in place to see what is going on (which I will past below). I expect to see the following happen (This works correctly on Absinthe 1.4 but not on Absinthe 1.5)
"*********************************************"
field_dentifier: :add_tag_value_to_transaction
map_get_parse_ids_root: :input
field_args: %{
input: %Absinthe.Type.Argument{
__reference__: %{
identifier: :input,
location: %{
file: "/Users/jacobparry/Divvy/repos/juno/apps/shared_api/lib/schema/mutations/transaction.ex",
line: 0
},
module: SharedAPI.Schema.Mutations.Transaction
},
default_value: nil,
deprecation: nil,
description: nil,
name: "input",
type: %Absinthe.Type.NonNull{of_type: :add_tag_value_to_transaction_input}
}
}
root_argument: :input
map_get_root_argument: %Absinthe.Type.Argument{
__reference__: %{
identifier: :input,
location: %{
file: "/Users/jacobparry/Divvy/repos/juno/apps/shared_api/lib/schema/mutations/transaction.ex",
line: 0
},
module: SharedAPI.Schema.Mutations.Transaction
},
default_value: nil,
deprecation: nil,
description: nil,
name: "input",
type: %Absinthe.Type.NonNull{of_type: :add_tag_value_to_transaction_input}
}
"*********************************************"
field_identifier: :tag_values
map_get_parse_ids_root: nil
I expect the parse_ids_root to be nil for the child fields that get resolved in the mutation.
mutation_before_parse: %{
client_mutation_id: "0",
tag_value_id: "VGFnVmFsdWU6MTAwMQ==",
transaction_id: "VHJhbnNhY3Rpb246Y2Q4MTY4ZjYtZmM3Zi00NjUwLTgwMGEtZGM5Zjg1YTQ2NWIw"
}
"*********************************************"
field_dentifier: :add_tag_value_to_transaction
map_get_parse_ids_root: :input
field_args: %{
input: %Absinthe.Type.Argument{
__reference__: nil,
default_value: nil,
definition: nil,
deprecation: nil,
description: nil,
identifier: :input,
name: "input",
type: %Absinthe.Type.NonNull{of_type: :add_tag_value_to_transaction_input}
}
}
root_argument: :input
map_get_root_argument: %Absinthe.Type.Argument{
__reference__: nil,
default_value: nil,
definition: nil,
deprecation: nil,
description: nil,
identifier: :input,
name: "input",
type: %Absinthe.Type.NonNull{of_type: :add_tag_value_to_transaction_input}
}
mutation_after_parse: %{
client_mutation_id: "0",
tag_value_id: 1001,
transaction_id: "cd8168f6-fc7f-4650-800a-dc9f85a465b0"
}
tags_before_parse: %{first: 10}
"*********************************************"
field_dentifier: :tag_values
map_get_parse_ids_root: :input
field_args: %{
after: %Absinthe.Type.Argument{
__reference__: nil,
default_value: nil,
definition: nil,
deprecation: nil,
description: nil,
identifier: :after,
name: "after",
type: :string
},
before: %Absinthe.Type.Argument{
__reference__: nil,
default_value: nil,
definition: nil,
deprecation: nil,
description: nil,
identifier: :before,
name: "before",
type: :string
},
first: %Absinthe.Type.Argument{
__reference__: nil,
default_value: nil,
definition: nil,
deprecation: nil,
description: nil,
identifier: :first,
name: "first",
type: :integer
},
last: %Absinthe.Type.Argument{
__reference__: nil,
default_value: nil,
definition: nil,
deprecation: nil,
description: nil,
identifier: :last,
name: "last",
type: :integer
},
tag_type_id: %Absinthe.Type.Argument{
__reference__: nil,
default_value: nil,
definition: nil,
deprecation: nil,
description: nil,
identifier: :tag_type_id,
name: "tag_type_id",
type: :id
}
}
root_argument: :input
map_get_root_argument: nil
In this result (Absinthe 1.5), we see that when the ParseIDs middleware tries to parse ids for the child field, it finds the parse_ids_root is still set as :input from the mutation, when it shouldn't. This behavior differs from Absinth 1.4.
Basically, the first ParseIDs works great parsing the IDs from the input object generated by the mutation. However, once the graph tries to parse the child field that also contains a ParseIDs middleware call, it blows up.
This results in a runtime error:
** (RuntimeError) Can't find ParseIDs schema root argument :input
stacktrace:
(shared_api 0.1.0) lib/absinthe/parse_ids.ex:259: Absinthe.SharedAPI.Absinthe.ParseIDs.find_schema_root!/2
(shared_api 0.1.0) lib/absinthe/parse_ids.ex:224: Absinthe.SharedAPI.Absinthe.ParseIDs.parse/3
(shared_api 0.1.0) lib/absinthe/parse_ids.ex:206: Absinthe.SharedAPI.Absinthe.ParseIDs.call/2
(absinthe 1.5.2) lib/absinthe/phase/document/execution/resolution.ex:230: Absinthe.Phase.Document.Execution.Resolution.reduce_resolution/1
(absinthe 1.5.2) lib/absinthe/phase/document/execution/resolution.ex:185: Absinthe.Phase.Document.Execution.Resolution.do_resolve_field/3
(absinthe 1.5.2) lib/absinthe/phase/document/execution/resolution.ex:170: Absinthe.Phase.Document.Execution.Resolution.do_resolve_fields/6
(absinthe 1.5.2) lib/absinthe/phase/document/execution/resolution.ex:88: Absinthe.Phase.Document.Execution.Resolution.walk_result/5
(absinthe 1.5.2) lib/absinthe/phase/document/execution/resolution.ex:280: Absinthe.Phase.Document.Execution.Resolution.build_result/3
(absinthe 1.5.2) lib/absinthe/phase/document/execution/resolution.ex:170: Absinthe.Phase.Document.Execution.Resolution.do_resolve_fields/6
(absinthe 1.5.2) lib/absinthe/phase/document/execution/resolution.ex:88: Absinthe.Phase.Document.Execution.Resolution.walk_result/5
(absinthe 1.5.2) lib/absinthe/phase/document/execution/resolution.ex:280: Absinthe.Phase.Document.Execution.Resolution.build_result/3
(absinthe 1.5.2) lib/absinthe/phase/document/execution/resolution.ex:170: Absinthe.Phase.Document.Execution.Resolution.do_resolve_fields/6
(absinthe 1.5.2) lib/absinthe/phase/document/execution/resolution.ex:88: Absinthe.Phase.Document.Execution.Resolution.walk_result/5
(absinthe 1.5.2) lib/absinthe/phase/document/execution/resolution.ex:67: Absinthe.Phase.Document.Execution.Resolution.perform_resolution/3
(absinthe 1.5.2) lib/absinthe/phase/document/execution/resolution.ex:24: Absinthe.Phase.Document.Execution.Resolution.resolve_current/3
(absinthe 1.5.2) lib/absinthe/pipeline.ex:368: Absinthe.Pipeline.run_phase/3
(absinthe_plug 1.5.0) lib/absinthe/plug.ex:445: Absinthe.Plug.run_query/4
(absinthe_plug 1.5.0) lib/absinthe/plug.ex:258: Absinthe.Plug.call/2
(phoenix 1.4.17) lib/phoenix/router.ex:288: Phoenix.Router.__call__/2
(user_api 0.1.0) lib/user_api/endpoint.ex:1: UserAPI.Endpoint.plug_builder_call/2
Relevant Schema/Middleware Code
Mutation being run. There is a ParseIDs middleware call on both :add_tag_value_to_transaction and on :tag_values.
mutation TestAddTagValueToTransaction($input: AddTagValueToTransactionInput!) {
addTagValueToTransaction(input: $input) {
transaction {
id
status
tagValues(first: 10) {
edges {
node {
id
}
}
}
}
}
}
"""
Mutation schema (notice the ParseIDs middleware):
payload field(:add_tag_value_to_transaction) do
input do
field(:transaction_id, non_null(:id))
field(:tag_value_id, :id, deprecate: "Use tagValueIds")
field(:tag_value_ids, list_of(:id))
end
output do
field(:transaction, :transaction)
end
middleware(fn res, _ ->
res.arguments |> IO.inspect(label: :mutation_before_parse)
res
end)
middleware(ParseIDs, transaction_id: :transaction, tag_value_id: :tag_value, tag_value_ids: :tag_value)
middleware(fn res, _ ->
res.arguments |> IO.inspect(label: :mutation_after_parse)
res
end)
resolve(&TagValueResolver.add_to_transaction/2)
end
Transaction node type (notice that this :tag_values field is part of the mutation query):
The mutation returns a transaction which then requests the child tag_values field.
node object :transaction do
...
connection field(:tag_values, node_type: :tag_value, deprecate: "Use `tags` instead") do
arg(:tag_type_id, :id)
middleware(fn res, _ ->
res.arguments |> IO.inspect(label: :tags_before_parse)
res
end)
middleware(ParseIDs, tag_type_id: :tag_type)
middleware(fn res, _ ->
res.arguments |> IO.inspect(label: :tags_after_parse)
res
end)
resolve(&TransactionRecordResolver.tag_values/2)
end
...
end
find_schema_root!/2 function with inspects so you can see what the output above is looking at:
@spec find_schema_root!(Field.t(), Resolution.t()) ::
{{Field.t() | Argument.t(), String.t()}, (String.t() -> String.t())}
defp find_schema_root!(field, resolution) do
IO.inspect("*********************************************")
IO.inspect(field.identifier, label: :field_dentifier)
Map.get(resolution.private, :__parse_ids_root)
|> IO.inspect(label: :map_get_parse_ids_root)
case Map.get(resolution.private, :__parse_ids_root) do
nil ->
{field, & &1}
root_argument ->
IO.inspect(field.args, label: :field_args)
IO.inspect(root_argument, label: :root_argument)
Map.get(field.args, root_argument)
|> IO.inspect(label: :map_get_root_argument)
argument =
Map.get(field.args, root_argument) ||
raise "Can't find ParseIDs schema root argument #{inspect(root_argument)}"
field_error_prefix = error_prefix(field, resolution.adapter)
argument_error_prefix = error_prefix(argument, resolution.adapter)
{argument,
&String.replace_leading(
&1,
field_error_prefix,
field_error_prefix <> argument_error_prefix
)}
end
end