CRUD: GraphQL with Elixir/Phoenix

I’m currently studying GraphQL with Elixir/Phoenix in preparation for this web and mobile app project. Although it’s easy to find tutorials on different sites, I’ve noticed that there’s no source discussing the CRUD process as a whole, so I’ve decided to do this article to combine each process altogether. Hope it helps.

In this example, we will focus on writing graphql queries and mutations for Phoenix App using Absinthe to be able to create, read, update and delete a Tag. Tag only has one field, to make the example quick and easy.

GraphQL Schema

Objects

First of all, we need to define the object and input_object, we will use both of them in most of our queries and mutations.

in schema.ex

# define your resolveralias ApiWeb.{
TagResolver
}
@desc “Tag data”
object :tag do
field :id, non_null(:id)
field :name, :string
end
# this input_object holds the parameter/s for the update method in our mutation input_object :tag_params do
field(:name, :string)
end

Queries

For the query part, we will define 2 queries: one that gets all the tags and another that gets the tag by id (the read part in crud).

in schema.ex

# Tag queriesquery do   field :tags, non_null(list_of(non_null(:tag))) do
arg :all, :boolean
resolve &TagResolver.all/3
end
field :tag, type: :tag do
arg :id, non_null(:id)
resolve &TagResolver.get/2
end
end

Mutations

After the query, we will now start writing our mutations for create, update, and delete tag.

still in schema.ex

mutation do   field :create_tag, type: :tag do
arg(:name, non_null(:string))
resolve(&TagResolver.create/2)
end
field :update_tag, type: :tag do
arg(:id, non_null(:id))
arg(:post, :tag_params)
resolve(&TagResolver.update/2)
end
field :delete_tag, type: :tag do
arg(:id, non_null(:id))
resolve(&TagResolver.delete/2)
end
end

In the :update_tag mutation, we use the :tag_params (the input_object we defined earlier) to hold the parameter values for the update method in the resolver.

GraphQL Resolver

After writing queries and mutations, let’s go ahead and write our resolvers for each of them in consecutive order.

in tag_resolver.ex

defmodule ApiWeb.TagResolver do # Define your elixir context 
alias Data.Contexts.TagContext, as: TC
def all(_root, _args, _info) do
{:ok, TC.all_tags}
end
def get(%{id: id}, _info) do
with {:ok, info} <- UUID.info(id),
tag <- TC.get(id)
do
{:ok, tag}
else
{:error, error} -> {:error, "No tag found"}
end
end
def create(tag_params, _info) do
with {:ok, tag} <- TC.insert(tag_params) do
{:ok, tag}
else
{:error, error} -> {:error, "Failed to create tag"}
end
end
def update(%{id: id, post: tag_params}, _info) do
case get(%{id: id}, _info) do
{:ok, post} -> post |> TC.modify(tag_params)
{:error, _} -> {:error, "Failed to update tag"}
end
end
def delete(%{id: id}, _info) do
with {:ok, post} <- TC.delete(id) do
{:ok, post}
else
{:error, _} -> {:error, "Failed to delete tag"}
end
end
end

Elixir Context

After the resolver, the last thing we need to do is to create the context methods we used in our resolvers.

in tag_context.ex

defmodule Data.Contexts.TagContext do   alias Data.Repo
alias Data.Schemas.Tag
import Ecto.Query
def all_tags() do
Tag
|> Repo.all
end
def get(id) do
Tag
|> Repo.get(id)
end
def insert(params) do
Tag.changeset(%Tag{}, params)
|> Repo.insert
end
def modify(struct, params) do
Tag.changeset(struct, params)
|> Repo.update
end

def delete(id) do
tag = Tag |> Repo.get(id)
Repo.delete(tag)
end
end

And we’re done !!!!

results in graphiql:

all_tags and tag_by_id read method
create tag mutation method
update tag mutation method
delete tag mutation method

Hope this article reaches someone like me. Happy Coding!!
Check out the full story on my website: CRUD: GraphQL in Elixir/Phoenix

I drink(☕️) and I code things — www.alvinrapada.com