Elixir

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