Skip to main content
Making Phoenix Errors Conform to the JSON API Spec

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

CAPTCHA This question is for testing whether or not you are a human visitor and to prevent automated spam submissions.
6 + 7 =
Solve this simple math problem and enter the result. E.g. for 1+3, enter 4.