defmodule GlificWeb.Schema.Middleware.ChangesetErrors do
@moduledoc """
Implementing middleware functions to transform errors from Ecto Changeset into a format
consumable and displayable to the API user. This version is specifically for mutations.
"""
@behaviour Absinthe.Middleware
@doc """
This is the main middleware callback.
It receives an %Absinthe.Resolution{} struct and it needs to return an %Absinthe.Resolution{} struct.
The second argument will be whatever value was passed to the middleware call that setup the middleware.
"""
@spec call(Absinthe.Resolution.t(), term()) :: Absinthe.Resolution.t()
def call(res, _) do
l = Map.get(res, :errors)
if length(l) == 2 do
[h | t] = l
%{res | value: %{errors: [%{key: h, message: t}]}, errors: []}
else
with %{errors: [%Ecto.Changeset{} = changeset]} <- res do
%{res | value: %{errors: transform_errors(changeset)}, errors: []}
end
end
end
@spec transform_errors(Ecto.Changeset.t()) :: Keyword.t()
defp transform_errors(changeset) do
changeset
|> Ecto.Changeset.traverse_errors(&format_error/1)
|> Enum.map(fn
{key, value} ->
key_msg = key |> Atom.to_string() |> String.capitalize()
%{key: key, message: "#{key_msg}: #{value}"}
end)
end
@spec format_error(Ecto.Changeset.error()) :: String.t()
defp format_error({msg, opts}) do
Enum.reduce(opts, msg, fn {key, value}, acc ->
String.replace(acc, "%{#{key}}", to_string(value))
end)
end
end