Building a GraphQL Server with Elixir and Absinthe
GraphQL has revolutionized the way APIs are designed by providing a flexible and efficient query language. When combined with Elixir’s concurrency model and Absinthe’s powerful GraphQL toolkit, you can build scalable and performant APIs. This article will guide you through building a GraphQL server using Elixir and Absinthe, complete with practical examples.
Understanding GraphQL and Elixir
GraphQL is a query language that allows clients to request specific data from an API, offering more flexibility than RESTful APIs. Elixir, with its scalability and concurrency model, is an excellent choice for building high-performance GraphQL servers. Absinthe is a GraphQL toolkit for Elixir that simplifies creating and managing GraphQL schemas and queries.
Setting Up Your Elixir Project
To begin, you’ll need to set up a new Elixir project with Absinthe. Here’s how to do it:
Step 1: Install Elixir and Phoenix
If you haven’t already, install Elixir and Phoenix, as Phoenix will be used to handle HTTP requests.
```bash mix archive.install hex phx_new ```
Step 2: Create a New Phoenix Project
Create a new Phoenix project and add Absinthe to your dependencies.
```bash mix phx.new graphql_server --no-ecto cd graphql_server ```
Add `:absinthe` and `:absinthe_plug` to your `mix.exs` dependencies:
```elixir defp deps do [ {:phoenix, "~> 1.6.0"}, {:absinthe, "~> 1.6.0"}, {:absinthe_plug, "~> 1.6.0"} ] end ```
Run `mix deps.get` to install the dependencies.
Defining Your GraphQL Schema
A GraphQL schema defines the types and queries available in your API. Let’s create a simple schema with a query to fetch user data.
Step 1: Create a Schema Module
In your `lib/graphql_server_web` directory, create a new file `schema.ex` and define your schema:
```elixir defmodule GraphqlServerWeb.Schema do use Absinthe.Schema query do field :user, :user do arg :id, non_null(:id) resolve &Resolvers.UserResolver.find/3 end end object :user do field :id, :id field :name, :string field :email, :string end end ```
Step 2: Create a Resolver
Resolvers handle the logic for your GraphQL queries. Let’s create a simple resolver to fetch user data.
```elixir defmodule GraphqlServerWeb.Resolvers.UserResolver do alias GraphqlServer.Users def find(_, %{id: id}, _) do case Users.get_user(id) do nil -> {:error, "User not found"} user -> {:ok, user} end end end ```
Setting Up a Phoenix Controller for GraphQL
To expose your GraphQL API, set up a Phoenix controller to handle the GraphQL queries.
Step 1: Create a GraphQL Controller
In `lib/graphql_server_web/controllers/graphql_controller.ex`, create a controller:
```elixir defmodule GraphqlServerWeb.GraphqlController do use GraphqlServerWeb, :controller use Absinthe.Phoenix.Controller def query(conn, params) do schema = GraphqlServerWeb.Schema result = Absinthe.run(params["query"], schema) json(conn, result) end end ```
Step 2: Set Up Routing
In `lib/graphql_server_web/router.ex`, add a route for the GraphQL queries:
```elixir scope "/api" do post "/graphql", GraphqlServerWeb.GraphqlController, :query end ```
Testing Your GraphQL API
With everything set up, you can now test your GraphQL API. Start your Phoenix server:
```bash mix phx.server ```
Use a GraphQL client like [GraphiQL](https://github.com/graphql/graphiql) or [Postman](https://www.postman.com/) to send a query:
```graphql query { user(id: "1") { id name email } } ```
Advanced Topics: Authentication and Authorization
To enhance your GraphQL API, consider adding authentication and authorization. Absinthe provides middleware for these purposes.
Example: Adding a Simple Authentication Middleware
```elixir defmodule GraphqlServerWeb.Middleware.Authenticate do def call(resolution, _) do case resolution.context[:current_user] do nil -> resolution |> Absinthe.Resolution.put_result({:error, "Not authenticated"}) _ -> resolution end end end ```
Use this middleware in your schema:
```elixir field :user, :user do arg :id, non_null(:id) middleware GraphqlServerWeb.Middleware.Authenticate resolve &Resolvers.UserResolver.find/3 end ```
Conclusion
Building a GraphQL server with Elixir and Absinthe combines the best of both worlds—GraphQL’s flexibility and Elixir’s performance. By following this guide, you’ve learned how to set up a GraphQL server, define schemas, create resolvers, and integrate with Phoenix. As you delve deeper, explore advanced topics like authentication, subscriptions, and optimizing queries for more robust and secure GraphQL APIs.
Further Reading:
Table of Contents