Absinthe
Absinthe is the GraphQL toolkit for Elixir, an implementation of the GraphQL specification built to suit the language’s capabilities and idiomatic style.
The GraphQL query
{
posts {
title
body
}
}
First, define a GraphQL schema, so we know what we can query
defmodule BlogWeb.Schema.ContentTypes do
use Absinthe.Schema.Notation
object :post do
field :id, :id
field :title, :string
field :body, :string
end
end
Then, we can make the query
defmodule BlogWeb.Schema do
use Absinthe.Schema
import_types BlogWeb.Schema.ContentTypes
alias BlogWeb.Resolvers
query do
@desc "Get all posts"
field :posts, list_of(:post) do
resolve &Resolvers.Content.list_posts/3
end
end
end
- I was confused about
&Resolvers.Content.list_posts/3
syntax - You can think of this as just passing the function pointer. it gives Absinthe a reference to the function, which it will later call when the client actually makes a graphQL query
Why is the query called a schema?
Cuz from a database background,
schema
is not really associated with queries.In GraphQL, the schema is a core concept that defines the shape of the data and possible operations that clients can perform via queries or mutation
- Revisit graphql schema
This lists posts is essentially the implementation that actually makes the SQL query!! under the hood, it’s this
defmodule BlogWeb.Resolvers.Content do
def list_posts(_parent, _args, _resolution) do
{:ok, Blog.Content.list_posts()}
end
end
This is very basic. We want to query for a specific id
{
user(id: "1") {
name
posts {
id
title
}
}
}
Absinthe types
Instead of this
defmodule MyAppWeb.Schema do
use Absinthe.Schema
object :user do
field :name, :string
end
# Rest of the schema...
end
Do this
defmodule MyAppWeb.Schema.AccountTypes do
use Absinthe.Schema.Notation
object :user do
field :name, :string
end
end
defmodule MyAppWeb.Schema do
use Absinthe.Schema
import_types MyAppWeb.Schema.AccountTypes
# Rest of the schema...
end
Interfaces
https://hexdocs.pm/absinthe/Absinthe.Type.Interface.html
Because sometimes it’s for the interface to determine the implementing type of a resolved object, you must either:
- Provide a :resolve_type function on the interface
- Provide a :is_type_of function on each implementing type
interface :named_entity do
field :name, :string
resolve_type fn
%{age: _}, _ -> :person
%{employee_count: _}, _ -> :business
_, _ -> nil
end
end
object :person do
field :name, :string
field :age, :string
interface :named_entity
end
object :business do
field :name, :string
field :employee_count, :integer
interface :named_entity
end