Absinthe.Schema.Notation (absinthe v1.6.4) View Source
Provides a set of macro's to use when creating a schema. Especially useful when moving definitions out into a different module than the schema itself.
Example
defmodule MyAppWeb.Schema.Types do
use Absinthe.Schema.Notation
object :item do
field :id, :id
field :name, :string
end
# ...
end
Link to this section Summary
Functions
Add an argument.
Add an argument.
Set the complexity of a field
Configure a subscription field.
Mark a field as deprecated
Defines a description
Defines a directive
Defines an enum type
Defines an enum type
Define the expansion for a directive
Defines a GraphQL field
Defines a GraphQL field
Defines a GraphQL field.
Import fields from another object
Import types defined using the Schema Definition Language (SDL).
Import types from another module
Defines an input object
Declare an implemented interface for an object.
Define an interface type.
Declare implemented interfaces for an object.
Placement
Allowed under: object
Marks a type reference as a list of the given type
Defines list of metadata's key/value pair for a custom type.
Defines a metadata key/value pair for a custom type.
Marks a type reference as non null
Define an object type.
Declare a directive as operating an a AST node type
Defines a parse function for a scalar
type
Set whether the directive can be applied multiple times an entity.
Defines a resolve function for a field
Define a type resolver for a union or interface.
Defines a scalar type
Define a scalar type
Defines a serialization function for a scalar
type
Sets triggers for a subscription, and configures which topics to publish to when that subscription is triggered.
Defines the types possible under a union type
Defines a union type
Defines a value possible under an enum type
Link to this section Types
Specs
Link to this section Functions
Add an argument.
See arg/3
Add an argument.
Placement
Allowed under: directive
field
Examples
field do
arg :size, :integer
arg :name, non_null(:string), description: "The desired name"
arg :public, :boolean, default_value: true
end
Set the complexity of a field
For a field, the first argument to the function you supply to complexity/1
is the user arguments -- just as a field's resolver can use user arguments to resolve its value, the complexity function that you provide can use the same arguments to calculate the field's complexity.
The second argument passed to your complexity function is the sum of all the complexity scores of all the fields nested below the current field.
An optional third argument is passed an Absinthe.Complexity
struct, which includes information
like the context passed to Absinthe.run/3
.
Placement
Allowed under: field
Examples
query do
field :people, list_of(:person) do
arg :limit, :integer, default_value: 10
complexity fn %{limit: limit}, child_complexity ->
# set complexity based on maximum number of items in the list and
# complexity of a child.
limit * child_complexity
end
end
end
Configure a subscription field.
The first argument to the config function is the field arguments passed in the subscription.
The second argument is an Absinthe.Resolution
struct, which includes information
like the context and other execution data.
Placement
Allowed under: field
Examples
config fn args, %{context: context} ->
if authorized?(context) do
{:ok, topic: args.client_id}
else
{:error, "unauthorized"}
end
end
Alternatively can provide a list of topics:
config fn _, _ ->
{:ok, topic: ["topic_one", "topic_two", "topic_three"]}
end
Using context_id
option to allow de-duplication of updates:
config fn _, %{context: context} ->
if authorized?(context) do
{:ok, topic: "topic_one", context_id: "authorized"}
else
{:ok, topic: "topic_one", context_id: "not-authorized"}
end
end
See Absinthe.Schema.subscription/1
for details
Mark a field as deprecated
In most cases you can simply pass the deprecate: "message" attribute. However when using the block form of a field it can be nice to also use this macro.
Placement
Allowed under: field
Examples
field :foo, :string do
deprecate "Foo will no longer be supported"
end
This is how to deprecate other things
field :foo, :string do
arg :bar, :integer, deprecate: "This isn't supported either"
end
enum :colors do
value :red
value :blue, deprecate: "This isn't supported"
end
Defines a description
This macro adds a description to any other macro which takes a block.
Note that you can also specify a description by using @desc
above any item
that can take a description attribute.
Placement
Allowed under any block. Not allowed to be top level
Defines a directive
Placement
Top level in module.
Examples
directive :mydirective do
arg :if, non_null(:boolean), description: "Skipped when true."
on [:field, :fragment_spread, :inline_fragment]
expand fn
%{if: true}, node ->
Blueprint.put_flag(node, :skip, __MODULE__)
_, node ->
node
end
end
Defines an enum type
See enum/3
Defines an enum type
Placement
Top level in module.
Examples
Handling RED
, GREEN
, BLUE
values from the query document:
enum :color do
value :red
value :green
value :blue
end
A given query document might look like:
{
foo(color: RED)
}
Internally you would get an argument in elixir that looks like:
%{color: :red}
If your return value is an enum, it will get serialized out as:
{"color": "RED"}
You can provide custom value mappings. Here we use r
, g
, b
values:
enum :color do
value :red, as: "r"
value :green, as: "g"
value :blue, as: "b"
end
Define the expansion for a directive
Placement
Allowed under: directive
Defines a GraphQL field
See field/4
Defines a GraphQL field
See field/4
Defines a GraphQL field.
Placement
Allowed under: input_object
interface
object
query
, mutation
, and subscription
are
all objects under the covers, and thus you'll find field
definitions under
those as well.
Examples
field :id, :id
field :age, :integer, description: "How old the item is"
field :name, :string do
description "The name of the item"
end
field :location, type: :location
Import fields from another object
Example
object :news_queries do
field :all_links, list_of(:link)
field :main_story, :link
end
object :admin_queries do
field :users, list_of(:user)
field :pending_posts, list_of(:post)
end
query do
import_fields :news_queries
import_fields :admin_queries
end
Import fields can also be used on objects created inside other modules that you have used import_types on.
defmodule MyApp.Schema.NewsTypes do
use Absinthe.Schema.Notation
object :news_queries do
field :all_links, list_of(:link)
field :main_story, :link
end
end
defmodule MyApp.Schema.Schema do
use Absinthe.Schema
import_types MyApp.Schema.NewsTypes
query do
import_fields :news_queries
# ...
end
end
Specs
import_sdl([import_sdl_option(), ...]) :: Macro.t()
Import types defined using the Schema Definition Language (SDL).
TODO: Explain handlers
Placement
Top level in module.
Examples
Directly embedded SDL:
import_sdl """
type Query {
posts: [Post]
}
type Post {
title: String!
body: String!
}
"""
Loaded from a file location (supporting recompilation on change):
import_sdl path: "/path/to/sdl.graphql"
TODO: Example for dynamic loading during init
Specs
import_sdl(String.t() | Macro.t(), [import_sdl_option()]) :: Macro.t()
Import types from another module
Very frequently your schema module will simply have the query
and mutation
blocks, and you'll want to break out your other types into other modules. This
macro imports those types for use the current module.
To selectively import types you can use the :only
and :except
opts.
Placement
Top level in module.
Examples
import_types MyApp.Schema.Types
import_types MyApp.Schema.Types.{TypesA, TypesB}
import_types MyApp.Schema.Types, only: [:foo]
import_types MyApp.Schema.Types, except: [:bar]
Defines an input object
Placement
Top level in module.
Examples
input_object :contact_input do
field :email, non_null(:string)
end
Declare an implemented interface for an object.
Adds an Absinthe.Type.Interface
to your schema.
See also interfaces/1
, which can be used for multiple interfaces,
and interface/3
, used to define interfaces themselves.
Examples
object :car do
interface :vehicle
# ...
end
Define an interface type.
Adds an Absinthe.Type.Interface
to your schema.
Also see interface/1
and interfaces/1
, which declare
that an object implements one or more interfaces.
Placement
Top level in module.
Examples
interface :vehicle do
field :wheel_count, :integer
end
object :rally_car do
field :wheel_count, :integer
interface :vehicle
end
Declare implemented interfaces for an object.
See also interface/1
, which can be used for one interface,
and interface/3
, used to define interfaces themselves.
Placement
Allowed under: interface
object
Examples
object :car do
interfaces [:vehicle, :branded]
# ...
end
Placement
Allowed under: object
Marks a type reference as a list of the given type
See field/3
for examples
Defines list of metadata's key/value pair for a custom type.
This is generally used to facilitate libraries that want to augment Absinthe functionality
Examples
object :user do
meta cache: true, ttl: 22_000
end
object :user, meta: [cache: true, ttl: 22_000] do
# ...
end
The meta can be accessed via the Absinthe.Type.meta/2
function.
user_type = Absinthe.Schema.lookup_type(MyApp.Schema, :user)
Absinthe.Type.meta(user_type, :cache)
#=> true
Absinthe.Type.meta(user_type)
#=> [cache: true, ttl: 22_000]
Placement
Allowed under: enum
field
input_object
interface
object
scalar
union
Defines a metadata key/value pair for a custom type.
For more info see meta/1
Examples
meta :cache, false
Placement
Allowed under: enum
field
input_object
interface
object
scalar
union
Marks a type reference as non null
See field/3
for examples
Define an object type.
Adds an Absinthe.Type.Object
to your schema.
Placement
Top level in module.
Examples
Basic definition:
object :car do
# ...
end
Providing a custom name:
object :car, name: "CarType" do
# ...
end
Declare a directive as operating an a AST node type
See directive/2
Placement
Allowed under: directive
Defines a parse function for a scalar
type
The specified parse
function is used on incoming data to transform it into
an elixir datastructure.
It should return {:ok, value}
or :error
Placement
Allowed under: scalar
Set whether the directive can be applied multiple times an entity.
If omitted, defaults to false
Placement
Allowed under: directive
Defines a resolve function for a field
Specify a 2 or 3 arity function to call when resolving a field.
You can either hard code a particular anonymous function, or have a function call that returns a 2 or 3 arity anonymous function. See examples for more information.
Note that when using a hard coded anonymous function, the function will not capture local variables.
3 Arity Functions
The first argument to the function is the parent entity.
{
user(id: 1) {
name
}
}
A resolution function on the name
field would have the result of the user(id: 1)
field
as its first argument. Top level fields have the root_value
as their first argument.
Unless otherwise specified, this defaults to an empty map.
The second argument to the resolution function is the field arguments. The final
argument is an Absinthe.Resolution
struct, which includes information like
the context
and other execution data.
2 Arity Function
Exactly the same as the 3 arity version, but without the first argument (the parent entity)
Placement
Allowed under: field
Examples
query do
field :person, :person do
resolve &Person.resolve/2
end
end
query do
field :person, :person do
resolve fn %{id: id}, _ ->
{:ok, Person.find(id)}
end
end
end
query do
field :person, :person do
resolve lookup(:person)
end
end
def lookup(:person) do
fn %{id: id}, _ ->
{:ok, Person.find(id)}
end
end
Define a type resolver for a union or interface.
See also:
Placement
Allowed under: interface
union
Examples
interface :entity do
# ...
resolve_type fn
%{employee_count: _}, _ ->
:business
%{age: _}, _ ->
:person
end
end
Defines a scalar type
See scalar/3
Define a scalar type
A scalar type requires parse/1
and serialize/1
functions.
Placement
Top level in module.
Examples
scalar :time, description: "ISOz time" do
parse &Timex.parse(&1.value, "{ISOz}")
serialize &Timex.format!(&1, "{ISOz}")
end
Defines a serialization function for a scalar
type
The specified serialize
function is used on outgoing data. It should simply
return the desired external representation.
Placement
Allowed under: scalar
Sets triggers for a subscription, and configures which topics to publish to when that subscription is triggered.
A trigger is the name of a mutation. When that mutation runs, data is pushed to the clients who are subscribed to the subscription.
A subscription can have many triggers, and a trigger can push to many topics.
Placement
Allowed under: field
Example
mutation do
field :gps_event, :gps_event
field :user_checkin, :user
end
subscription do
field :location_update, :user do
arg :user_id, non_null(:id)
config fn args, _ ->
{:ok, topic: args.user_id}
end
trigger :gps_event, topic: fn gps_event ->
gps_event.user_id
end
# Trigger on a list of mutations
trigger [:user_checkin], topic: fn user ->
# Returning a list of topics triggers the subscription for each of the topics in the list.
[user.id, user.friend.id]
end
end
end
Trigger functions are only called once per event, so database calls within them do not present a significant burden.
See the Absinthe.Schema.subscription/2
macro docs for additional details
Defines the types possible under a union type
See union/3
Placement
Allowed under: union
Defines a union type
Placement
Top level in module.
Examples
union :search_result do
description "A search result"
types [:person, :business]
resolve_type fn
%Person{}, _ -> :person
%Business{}, _ -> :business
end
end
Defines a value possible under an enum type
See enum/3
Placement
Allowed under: enum