View Source Absinthe.Relay.Node.ParseIDs (absinthe_relay v1.5.2)

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 :id and 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

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
end

Parse 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
end

Parse 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
end

As 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

end

using-with-mutations

Using 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

end

Needs 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
end

If, 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

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.

Link to this section Summary

Types

The rules used to parse node ID arguments.

Link to this section Types

Specs

full_result() :: %{type: atom(), id: simple_result()}

Specs

result() :: full_result() | simple_result()

Specs

rules() ::
  [{atom(), atom() | [atom()]}] | %{required(atom()) => atom() | [atom()]}

The rules used to parse node ID arguments.

examples

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.

Specs

simple_result() :: nil | binary()

Link to this section Functions

Link to this function

find_schema_root!(field, resolution)

View Source

Specs