Code:: Making Phoenix Errors Conform to the JSON API Spec
Over the past few weeks I have been building an API using the fantastic Phoenix framework. Overall, my experience has been very good. Along with the Phoenix API, I am building a frontend that is written in Ember (using Ember-Data) to consume this API.
By default, the Phoenix endpoints do not render a payload that conforms to the JSON API specification. This is actually fine by me since I prefer returning standard, easy to understand JSON responses. Ember (Ember-Data to be more specific), is not totally OK with this. By using DS.RESTAdapter
instead of DS.JSONAPIAdapter
, and DS.RESTSerializer
instead of DS.JSONAPISerializer
, everything works pretty well for the most part...except for when an error is returned.
Ember-Data, at least as of version 3.0, expects errors to be returned how JSON API errors are returned. By default, Phoenix returns errors that look like this:
{
"errors": {
"username": "already in use"
}
}
If your API returns errors that look like this, Ember will not be able to inserts these errors into the model. It will say "Assertion Failed: `AdapterError` expects json-api formatted errors array."
To fix this, we must add some lines to our changeset_view.ex
file in our Phoenix application.
Let's change your translate_errors
function to look like this:
def translate_errors(changeset) do
errors = Ecto.Changeset.traverse_errors(changeset, &translate_error/1)
errors
|> Enum.map(fn {attribute, detailArray} -> Enum.map(detailArray, fn detail -> %{source: %{pointer: "data/attributes/" <> Atom.to_string(attribute)}, detail: detail} end) end)
|> List.flatten
end
Once you do this, your errors will return a payload that looks like the following:
{
"errors":
[
{
"source": {"pointer": "data/attributes/username"},
"detail":"has already been taken"
}
]
}
...which makes Ember very happy!
Hope this helped someone!
Add new comment