Default a scope to JSON on error (and data returnal)

How does one default a scope to render errors as JSON? Currently it seems to default to html, thus whenever an error occurs it’s renderring XXX.html.

How about data, I suppose json/2 is the way to go when sending a response back to the client?

It defaults to rendering whatever you return. ^.^

If you want to, say, render a different error style based on the format, well you can check the requested format and return a specialized return body (defaulting to whatever). :slight_smile:

:thinking: What I am aiming for is having an /api endpoint (or scope) that returns regular data or a message in case there was an error, both as JSON.

Currently any error raising inside the api scope is being renderred as its .html version, is it possible to configure the scope to instead do .json? perhaps a way to catch any error happening inside a scope? any other approach?

In the config/config.exs file, there is a render_errors entry (for your app’s config). Make sure it has accepts ~w(json), and not accepts ~w(html json).

2 Likes

Be aware though that some response codes are limited to return HTML as per rfc. I had to look those up though

2 Likes

I’ve been struggling with the same problem for the past couple of hours. As far as my knowledge goes, using accepts ~w(json) in your endpoint configuration is useless as you want to render HTML and JSON depending on the scope.

Hovewer, the following works for me:


Use :api pipeline for your /api scope

pipeline :api do
    plug :accepts, ["json"]
end
scope "/api", as: :api do
    pipe_through [:api]
    ...
end

Define functions for any of the errors (404, 500, etc.) you want to render as JSON in your project’s ErrorView

def render("404.json", _assings) do
    %{errors: %{message: "Resource not found"}}
end

Finally, make sure that requests to your API have Accept header field set to application/json.


Please note that I’m a Phoenix/Elixir beginner. I’m not familiar with any solution that would allow us to enforce JSON responses for common errors (404, 500) per scope, no matter what is the Accept header field’s value.

Any comments and suggestions for possible improvements are more than welcome.

I have been doing a bit of research through Phoenix’ source code and found out:

  • Errors are handled and rendered using a format param here.
  • Which is obtained here, from a function that expects conn params.
  • Which are set down here when the accepts plug is invoked.

Now, before raising an error in a controller, I am able to confirm phoenix_format is set to json. What happens next is it tries to render the error but with the format being html instead.

Therefore, Phoenix might be ignoring the changes made to the Plug.Conn structure when the plug pipeline halts somewhere. Here goes a gist for reference.

2 Likes

As I recall (I may be wrong) but the HTML spec requires HTML to be sent on many error status codes (don’t recall which ones off hand).