Skip to content

Instantly share code, notes, and snippets.

@jherdman
Created August 10, 2020 13:13
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jherdman/d6c89166d4d427108629ec3d1618d199 to your computer and use it in GitHub Desktop.
Save jherdman/d6c89166d4d427108629ec3d1618d199 to your computer and use it in GitHub Desktop.
defmodule RovrApiWeb.ChangesetView do
use RovrApiWeb, :view
@doc """
Traverses and translates changeset errors.
See `Ecto.Changeset.traverse_errors/2` and
`RovrApiWeb.ErrorHelpers.translate_error/1` for more details.
"""
def translate_errors(changeset) do
Ecto.Changeset.traverse_errors(changeset, &translate_error/1)
end
@doc ~S"""
Converts a map of errors into a JSON:API collection of error objects
## Examples
iex> jsonapi_error_objects(%{name: ["can't be blank"], url: ["can't be blank"]})
[
%{
"title" => "can't be blank",
"source" => %{"pointer" => "/data/attributes/name"}
},
%{
"title" => "can't be blank",
"source" => %{"pointer" => "/data/attributes/url"}
}
]
iex> jsonapi_error_objects(%{feed_id: ["does not exist"]})
[
%{
"title" => "does not exist",
"source" => %{"pointer" => "/data/relationships/feed"}
}
]
"""
@spec jsonapi_error_objects(errors :: map()) :: [map()]
def jsonapi_error_objects(errors) do
errors
|> Enum.map(fn {attr, errs} ->
{get_pointer(attr), errs}
end)
|> Enum.flat_map(fn {pointer, errs} ->
Enum.map(errs, fn err ->
%{
"title" => err,
"source" => %{
"pointer" => pointer
}
}
end)
end)
end
defp get_pointer(attr) when is_atom(attr), do: get_pointer(Atom.to_string(attr))
defp get_pointer(attr) do
attr = JSONAPI.Utils.String.camelize(attr)
if String.ends_with?(attr, "Id") do
attr = String.replace_trailing(attr, "Id", "")
"/data/relationships/#{attr}"
else
"/data/attributes/#{attr}"
end
end
def render("error.json", %{changeset: changeset}) do
errors =
changeset
|> translate_errors()
|> jsonapi_error_objects()
# When encoded, the changeset returns its errors
# as a JSON object. So we just pass it forward.
%{errors: errors}
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment