Absinthe is an Elixir implementation of a GraphQL server. See:
Add absinthe
to your mix.exs
, then run mix deps.get
.
def apps(_default) do
[
:absinthe,
:absinthe_plug
]
end
defp deps do
[
{:absinthe, "~> 1.3.2"},
{:absinthe_plug, "~> 1.3.0"},
{:absinthe_ecto, "~> 0.1.2"}
]
end
graphql
| mutation
| user_mutations.ex
| query
| user_queries.ex
| resolver
| user_resolver.ex
| type
| user_types.ex
| schema.ex
| graphql.ex
scope "/" do
# Your plugs and other stuff here
if Mix.env == :dev do
forward "/graphiql", Absinthe.Plug.GraphiQL, schema: MyApp.GraphQL.Schema
else
forward "/graphql", Absinthe.Plug, schema: MyApp.GraphQL.Schema
end
end
defmodule MyApp.GraphQL do
@moduledoc """
A module that keeps using definitions for graphql components.
"""
def type do
quote do
use Absinthe.Schema.Notation
use Absinthe.Ecto, repo: MyApp.Repo
end
end
def query do
quote do
use Absinthe.Schema.Notation
end
end
def schema do
quote do
use Absinthe.Schema
end
end
def resolver do
quote do
alias MyApp.Repo
end
end
@doc """
When used, dispatch to the appropriate controller/view/etc.
"""
defmacro __using__(which) when is_atom(which) do
apply(__MODULE__, which, [])
end
end
defmodule MyApp.GraphQL.Schema do
use MyApp.GraphQL, :schema
alias MyApp.GraphQL.{
Query.UserQueries,
Mutation.UserMutations.
Type.UserType
}
# Import everything on the schema since Absinthe will throw an error on compile if you have multiple imports of the same module spread across multiple files
import_types UserQueries
import_types UserMutations
import_types UserType
query do
import_fields :user_queries
end
mutation do
import_fields :user_mutations
end
end
defmodule MyApp.GraphQL.Query.UserQueries do
use MyApp.GraphQL, :query
alias MyApp.GraphQL.Resolver.UserResolver
object :user_queries do
@desc "Get all users"
field :users, list_of(:user) do
resolve &UserResolver.all/2
end
@desc "Get user with id"
field :user, type: :user do
arg :id, non_null(:id)
resolve &UserResolver.find/2
end
end
end
defmodule MyApp.GraphQL.Type.UserType do
use MyApp.GraphQL, :type
object :user do
field :id, :id
field :first_name, :string
field :last_name, :string
field :email, :string
field :projects, list_of(:project), resolve: assoc(:projects) # Defined under project_type.ex
end
end
defmodule MyApp.GraphQL.Resolver.UserResolver do
use MyApp.GraphQL, :resolver
alias MyApp.User
def all(_args, _info) do
{:ok, Repo.all(User)}
end
def find(%{id: id}, _info) do
case Repo.get(User, id) do
nil -> {:error, "User not found"}
user -> {:ok, user}
end
end
end