absinthe_relay_oxo v1.2.1 Absinthe.Relay.Node
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:
- https://facebook.github.io/relay/docs/graphql-object-identification.html#content
- https://facebook.github.io/relay/graphql/objectidentification.htm
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
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 easly create object types that can be looked up using this field:
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;
a Base64 string that’s built using the object type name and the raw, internal
identifier. All of this is handled for you automatically by prefixing your
object type definition with "node "
.
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
Macros
For more details on node-related macros, see
Absinthe.Relay.Node.Notation
.
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
Functions
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 returnsnil
- If it’s not nil, it coerces it to a binary using
Kernel.to_string/1
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
Specs
from_global_id(binary, atom) ::
{:ok, %{type: atom, id: binary}} |
{:error, binary}
Parse a global ID, given a schema.
Examples
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"}
Specs
to_global_id(atom | binary, integer | binary | nil) ::
binary |
nil
Generate a global ID given a node type name and an internal (non-global) ID
Examples
iex> to_global_id("Person", "123")
"UGVyc29uOjEyMw=="
iex> to_global_id(:person, "123", SchemaWithPersonType)
"UGVyc29uOjEyMw=="
iex> to_global_id(:person, nil, SchemaWithPersonType)
"No source non-global ID value given"