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

Support for global object identification.

The node macro can be used by schema designers to add required "object identification" support for object types, and to provide a unified interface for querying them.

More information can be found at:

interface

Interface

Define a node interface for your schema, providing a type resolver that, given a resolved object can determine which node object type it belongs to.

node interface do
  resolve_type fn
    %{age: _}, _ ->
      :person
    %{employee_count: _}, _ ->
      :business
    _, _ ->
      nil
  end
end

This will create an interface, :node that expects one field, :id, be defined -- and that the ID will be a global identifier.

If you use the node macro to create your object types (see "Object" below), this can be easily done, layered on top of the standard object type definition style.

field

Field

The node field provides a unified interface to query for an object in the system using a global ID. The node field should be defined within your schema query and should provide a resolver that, given a map containing the object type identifier and internal, non-global ID (the incoming global ID will be parsed into these values for you automatically) can resolve the correct value.

query do

  # ...

  node field do
    resolve fn
      %{type: :person, id: id}, _ ->
        {:ok, Map.get(@people, id)}
      %{type: :business, id: id}, _ ->
        {:ok, Map.get(@businesses, id)}
    end
  end

end

This creates a field, :node, with one argument: :id. This is expected to be a global ID and, once resolved, will result in a value whose type implements the :node interface.

Here's how you easily create object types that can be looked up using this field:

object

Object

To play nicely with the :node interface and field, explained above, any object types need to implement the :node interface and generate a global ID as the value of its :id field. Using the node macro, you can easily do this while retaining the usual object type definition style.

node object :person do
  field :name, :string
  field :age, :string
end

This will create an object type, :person, as you might expect. An :id field is created for you automatically, and this field generates a global ID; an opaque string that's built using a global ID translator (by default a Base64 implementation). All of this is handled for you automatically by prefixing your object type definition with "node ".

By default, type of :id field is ID. But you can pass custom type in :id_type attribute:

node interface id_type: :uuid do
    resolve_type fn
      ...
    end
end

node field id_type: :uuid do
    resolve fn
      ...
    end
end

node object :thing, id_type: :uuid do
  field :name, :string
end

Or you can set it up globally via application config:

config Absinthe.Relay,
  node_id_type: :uuid

The raw, internal value is retrieved using default_id_fetcher/2 which just pattern matches an :id field from the resolved object. If you need to extract/build an internal ID via another method, just provide a function as an :id_fetcher option.

For instance, assuming your raw internal IDs were stored as :_id, you could configure your object like this:

node object :thing, id_fetcher: &my_custom_id_fetcher/2 do
  field :name, :string
end

For instructions on how to change the underlying method of decoding/encoding a global ID, see Absinthe.Relay.Node.IDTranslator.

macros

Macros

For more details on node-related macros, see Absinthe.Relay.Node.Notation.

Link to this section Summary

Functions

The default ID fetcher used to retrieve raw, non-global IDs from values.

Parse a global ID, given a schema.

Generate a global ID given a node type name and an internal (non-global) ID given a schema.

Link to this section Types

Specs

global_id() :: binary()

Link to this section Functions

Link to this function

default_id_fetcher(arg1, arg2)

View Source

Specs

default_id_fetcher(any(), Absinthe.Resolution.t()) :: nil | binary()

The default ID fetcher used to retrieve raw, non-global IDs from values.

  • Matches :id out of the value.
    • If it's nil, it returns nil
    • If it's not nil, it coerces it to a binary using Kernel.to_string/1

examples

Examples

iex> default_id_fetcher(%{id: "foo"})
"foo"
iex> default_id_fetcher(%{id: 123})
"123"
iex> default_id_fetcher(%{id: nil})
nil
iex> default_id_fetcher(%{nope: "no_id"})
nil
Link to this function

from_global_id(global_id, schema)

View Source

Specs

from_global_id(nil, Absinthe.Schema.t()) :: {:ok, nil}
from_global_id(global_id(), Absinthe.Schema.t()) ::
  {:ok, %{type: atom(), id: binary()}} | {:error, binary()}

Parse a global ID, given a schema.

To change the underlying method of decoding a global ID, see Absinthe.Relay.Node.IDTranslator.

examples

Examples

For nil, pass-through:

iex> from_global_id(nil, Schema)
{:ok, nil}

For a valid, existing type in Schema:

iex> from_global_id("UGVyc29uOjE=", Schema)
{:ok, %{type: :person, id: "1"}}

For an invalid global ID value:

iex> from_global_id("GHNF", Schema)
{:error, "Could not decode ID value `GHNF'"}

For a type that isn't in the schema:

iex> from_global_id("Tm9wZToxMjM=", Schema)
{:error, "Unknown type `Nope'"}

For a type that is in the schema but isn't a node:

iex> from_global_id("Tm9wZToxMjM=", Schema)
{:error, "Type `Item' is not a valid node type"}
Link to this function

to_global_id(node_type, source_id, schema \\ nil)

View Source

Specs

to_global_id(
  atom() | binary(),
  integer() | binary() | nil,
  Absinthe.Schema.t() | nil
) :: global_id() | nil

Generate a global ID given a node type name and an internal (non-global) ID given a schema.

To change the underlying method of encoding a global ID, see Absinthe.Relay.Node.IDTranslator.

examples

Examples

iex> to_global_id("Person", "123")
"UGVyc29uOjEyMw=="
iex> to_global_id(:person, "123", SchemaWithPersonType)
"UGVyc29uOjEyMw=="
iex> to_global_id(:person, nil, SchemaWithPersonType)
nil