Absinthe GraphQL Toolkit
Absinthe is a powerful GraphQL toolkit for Elixir, a functional programming language built on top of the Erlang virtual machine.
It allows developers to build flexible and efficient APIs by leveraging the GraphQL query language. In this tutorial, we will explore the history, features, and several examples of Absinthe.
History of Absinthe
Absinthe was created by Ben Wilson and Bruce Williams in 2016 as an open-source project. It was developed to provide Elixir developers with a seamless way to build GraphQL APIs. Since its release, Absinthe has gained popularity within the Elixir community and has become the go-to framework for GraphQL development in Elixir.
Features of Absinthe
Absinthe offers a wide range of features that make it a powerful tool for building GraphQL APIs:
Schema Definition Language (SDL): Absinthe provides a clean and concise syntax for defining your GraphQL schema using SDL. SDL allows you to define types, queries, mutations, and subscriptions in a human-readable format.
defmodule MyApp.Schema do
use Absinthe.Schema
schema """
type Query {
hello: String
}
"""
endIn the above example, we define a simple schema with a single query field
hellothat returns a string.Resolvers: Absinthe allows you to define resolvers for your schema fields. Resolvers are responsible for fetching the data for a particular field. You can define resolvers using plain Elixir functions or by using the
Absinthe.Resolutionmacro.defmodule MyApp.Schema do
use Absinthe.Schema
schema """
type Query {
hello: String
}
"""
def hello(_, _) do
"Hello, World!"
end
endIn the above example, we define a resolver for the
helloquery field that returns the string "Hello, World!".Input Objects: Absinthe supports input objects, which allow you to pass complex arguments to your queries and mutations. Input objects can have multiple fields with different types.
input_object :user_input do
field :name, non_null(:string)
field :age, :integer
endIn the above example, we define an input object
user_inputwith two fields:nameof typeString!(non-null string) andageof typeInteger.Middleware: Absinthe provides a middleware system that allows you to customize the behavior of your GraphQL API. Middleware functions can be used for authentication, authorization, logging, and more.
defmodule MyApp.AuthenticationMiddleware do
def call(resolution, _) do
# Perform authentication logic here
resolution
end
endIn the above example, we define a simple authentication middleware that performs authentication logic before resolving the GraphQL query.
Subscriptions: Absinthe supports real-time updates through GraphQL subscriptions. Subscriptions allow clients to subscribe to specific events and receive updates when those events occur.
subscription :newMessageAdded, :message do
# Subscription resolution logic
endIn the above example, we define a subscription
newMessageAddedthat resolves to amessageobject.
Examples of Absinthe
Now let's explore some practical examples of Absinthe to better understand its features.
Example 1: Getting Started
To get started with Absinthe, you need to add the
absintheandabsinthe_plugdependencies to your project. Then, you can define your schema and mount it as a plug in your Phoenix application.# mix.exs
defp deps do
[
{:absinthe, "~> 1.6"},
{:absinthe_plug, "~> 1.6"}
]
end# lib/my_app_web/router.ex
pipeline :api do
plug :accepts, ["json"]
end
scope "/api" do
pipe_through :api
forward "/graphql", Absinthe.Plug,
schema: MyApp.Schema
endIn the above example, we define a basic setup for integrating Absinthe with a Phoenix application.
Example 2: Querying Data
Let's define a schema with a query field to fetch a list of users from a database.
schema """
type Query {
users: [User!]
}
type User {
id: ID!
name: String!
email: String!
}
"""Now, we can define a resolver function to fetch the list of users from the database.
def users(_, _) do
users = MyApp.Repo.all(MyApp.User)
{:ok, users}
endIn the above example, the resolver function
usersfetches all the users from the database using Ecto (Elixir's database wrapper). The fetched users are then returned as a list.Example 3: Mutations
We can also define mutations to create, update, or delete data. Let's define a mutation to create a new user.
schema """
type Mutation {
createUser(input: UserInput!): User!
}
input UserInput {
name: String!
email: String!
}
"""Now, we can define a resolver function to handle the
createUsermutation.def create_user(_, %{input: %{"name" => name, "email" => email}}) do
user = MyApp.Repo.insert(MyApp.User.changeset(%MyApp.User{}, %{name: name, email: email}))
{:ok, user}
endIn the above example, the resolver function
create_usertakes thenameandemailfrom the input argument and inserts a new user into the database using Ecto.
These examples provide a glimpse into the power and flexibility of Absinthe for building GraphQL APIs in Elixir. For more information and advanced usage, refer to the official Absinthe documentation: Absinthe Documentation
In conclusion, Absinthe is a feature-rich and highly customizable GraphQL toolkit for Elixir. Its intuitive syntax, powerful features, and seamless integration with Elixir make it an excellent choice for building scalable and efficient GraphQL APIs.