View Source Absinthe.Relay.Node.ParseIDs (absinthe_relay v1.6.0)
Parse node (global) ID arguments before they are passed to a resolver, checking the arguments against acceptable types.
For each argument:
- If a single node type is provided, the node ID in the argument map will be replaced by the ID specific to your application.
- If multiple node types are provided (as a list), the node ID in the
argument map will be replaced by a map with the node ID specific to your
application as
:idand the parsed node type as:type.
If a GraphQL null value for an ID is found, it will be passed through as
nil in either case, since no type can be associated with the value.
Examples
Parse a node (global) ID argument :item_id as an :item type. This replaces
the node ID in the argument map (key :item_id) with your
application-specific ID. For example, "123".
field :item, :item do
arg :item_id, non_null(:id)
middleware Absinthe.Relay.Node.ParseIDs, item_id: :item
resolve &item_resolver/3
endParse a node (global) ID argument :interface_id into one of multiple node
types. This replaces the node ID in the argument map (key :interface_id)
with map of the parsed node type and your application-specific ID. For
example, %{type: :thing, id: "123"}.
field :foo, :foo do
arg :interface_id, non_null(:id)
middleware Absinthe.Relay.Node.ParseIDs, interface_id: [:item, :thing]
resolve &foo_resolver/3
endParse a nested structure of node (global) IDs. This behaves similarly to the examples above, but acts recursively when given a keyword list.
input_object :parent_input do
field :id, non_null(:id)
field :children, list_of(:child_input)
field :child, non_null(:child_input)
end
input_object :child_input do
field :id, non_null(:id)
end
mutation do
payload field :update_parent do
input do
field :parent, :parent_input
end
output do
field :parent, :parent
end
middleware Absinthe.Relay.Node.ParseIDs, parent: [
id: :parent,
children: [id: :child],
child: [id: :child]
]
resolve &resolve_parent/2
end
endAs with any piece of middleware, this can configured schema-wide using the
middleware/3 function in your schema. In this example all top level
query fields are made to support node IDs with the associated criteria in
@node_id_rules:
defmodule MyApp.Schema do
# Schema ...
@node_id_rules [
item_id: :item,
interface_id: [:item, :thing],
]
def middleware(middleware, _, %Absinthe.Type.Object{identifier: :query}) do
[{Absinthe.Relay.Node.ParseIDs, @node_id_rules} | middleware]
end
def middleware(middleware, _, _) do
middleware
end
endUsing with Mutations
Important: Remember that middleware is applied in order. If you're
using middleware/3 to apply this middleware to a mutation field
(defined using the Absinthe.Relay.Mutation macros) before the
Absinthe.Relay.Mutation middleware, you need to include a wrapping
top-level :input, since the argument won't be stripped out yet.
So, this configuration defined inside of a payload field block:
mutation do
payload field :change_something do
# ...
middleware Absinthe.Relay.Node.ParseIDs, profile: [
user_id: :user
]
end
endNeeds to look like this if you put the ParseIDs middleware first:
def middleware(middleware, %Absinthe.Type.Field{identifier: :change_something}, _) do
# Note the addition of the `input` level:
[{Absinthe.Relay.Node.ParseIDs, input: [profile: [user_id: :user]]} | middleware]
end
def middleware(middleware, _, _) do
middleware
endIf, however, you do a bit more advanced surgery to the middleware
list and insert Absinthe.Relay.Node.ParseIDs after
Absinthe.Relay.Mutation, you don't include the wrapping :input.
Compatibility Note for Middleware Developers
If you're defining a piece of middleware that modifies field
arguments similar to Absinthe.Relay.Mutation does (stripping the
outer input argument), you need to set the private
:__parse_ids_root so that this middleware can find the root schema
node used to apply its configuration. See Absinthe.Relay.Mutation
for an example of setting the value, and the find_schema_root!/2
function in this module for how it's used.
Summary
Types
@type full_result() :: %{type: atom(), id: simple_result()}
@type result() :: full_result() | simple_result()
The rules used to parse node ID arguments.
Examples
Declare :item_id as only valid with the :item node type:
[
item_id: :item
]Declare :item_id be valid as either :foo or :bar types:
[
item_id: [:foo, :bar]
]Note that using these two different forms will result in different argument
values being passed for :item_id (the former, as a binary, the latter
as a map).
In the event that the ID is a null, it will be passed-through as nil.
See the module documentation for more details.
@type simple_result() :: nil | binary()
Functions
@spec find_schema_root!(Absinthe.Type.Field.t(), Absinthe.Resolution.t()) :: {{Absinthe.Type.Field.t() | Absinthe.Type.Argument.t(), String.t()}, (String.t() -> String.t())}