View Source Writing Schemas
A GraphQL API starts by building a schema. Using Absinthe, schemas are normal
modules that use Absinthe.Schema.
Here's a schema that supports looking up an item by ID:
# filename: myapp/schema.ex
defmodule MyAppWeb.Schema do
use Absinthe.Schema
# Example data
@items %{
"foo" => %{id: "foo", name: "Foo"},
"bar" => %{id: "bar", name: "Bar"}
}
query do
field :item, :item do
arg :id, non_null(:id)
resolve fn %{id: item_id}, _ ->
{:ok, @items[item_id]}
end
end
end
endYou may want to refer to the Absinthe API documentation for more detailed information as you look this over.
Some macros and functions used here that are worth mentioning, pulled in automatically from
Absinthe.Schema.Notation by use Absinthe.Schema:
query- Defines the root query object. It's like usingobjectbut with nice defaults. There is a matchingmutationmacro as well.field- Defines a field in the enclosingobject,input_object, orinterface.arg- Defines an argument in the enclosingfieldordirective.resolve- Sets the resolve function for the enclosingfield.
You'll notice we mention some types being referenced: :item and :id. :id
is a built-in scalar type (like :string, :boolean, and others), but :item
we need to define ourselves.
We can do it in the same MyAppWeb.Schema module, using the object macro defined by Absinthe.Schema.Notation:
# filename: myapp/schema.ex
@desc "An item"
object :item do
field :id, :id
field :name, :string
endNow you can use Absinthe to execute a query document. Keep in mind that for
HTTP, you'll probably want to use
Absinthe.Plug instead of executing
GraphQL query documents yourself. Absinthe doesn't know or care about HTTP,
but the absinthe_plug project does: it handles the vagaries of interacting
with HTTP GraphQL clients so you don't have to.
If you were executing query documents yourself (let's assume for a local tool), it would go something like this:
"""
{
item(id: "foo") {
name
}
}
"""
|> Absinthe.run(MyAppWeb.Schema)
# Result
{:ok, %{data: %{"item" => %{"name" => "Foo"}}}}Your schemas can be further customized using the options available to
Absinthe.Schema.Notation.field/4 to help provide for a richer experience for
your users, customize the field names, or mark fields as deprecated.
# filename: myapp/language_schema.ex
@desc "A Language"
object :language do
field :id, :id
field :iso_639_1, :string, description: "2 character ISO 639-1 code", name: "iso639"
field :name, :string, description: "English name of the language"
endImporting Types
We could also move our type definitions out into a different module, for instance, MyAppWeb.Schema.Types, and then use import_types in our MyAppWeb.Schema:
# filename: myapp/schema/types.ex
defmodule MyAppWeb.Schema.Types do
use Absinthe.Schema.Notation
object :item do
field :id, :id
field :name, :string
end
# ...
end
# filename: myapp/schema.ex
defmodule MyAppWeb.Schema do
use Absinthe.Schema
import_types MyAppWeb.Schema.Types
# ...
endIt's a nice way of separating the top-level query and mutation information,
which define the surface area of the API, with the actual types that it uses.
See Importing Types for a full guide to importing types.