4
votes

In my current Phoenix project I have both a :browser pipeline and a :api pipeline. I want to render different error messages for each pipeline. However, I'm not sure how to achieve it.

My router.ex is like:

  scope "/api", AppWeb do
    pipe_through(:api)
    # ...
  end

  scope "/admin", AppWeb do
    pipe_through :browser
    # ...
  end

I want all requests to non-existing routes under /admin to render a HTTP error template, but all requests to any other route to render a JSON error template.

In config.exs I have

render_errors: [view: AppWeb.ErrorView, accepts: ~w(json html)]

However, I'm not sure how to proceed with the error view.

It seems that the template_not_found/2 function will be automatically called, whenever a routing error occurs, however, this function doesn't have a conn argument. Its arguments are template and assigns.

Should I try to inspect the assigns to try to determine which route the incoming request was trying to access? Trying to inspect the template didn't seem to be helpful, and the template attempted to be rendered all seem to end with .html extension, even if I try to visit a route under /api.

1
Are you accessing it from the browser? The browser gives the HTML content-type higher priority and therefore, once we have to negotiate which format to use, we will pick it up. However, if you do a request with curl and set Accept: application/json header, like an API client would, then you should get JSON back.José Valim
@JoséValim Thanks. Setting the header worked.xji

1 Answers

2
votes

As @JoséValim pointed out, the reason why I didn't correctly see JSON error messages is because I was visiting the pages via a browser. If I correctly set the header Accept: application/json in my request, it worked.

In template_not_found function in error_view.ex, it seems to suffice to just write Phoenix.Controller.status_message_from_template(template).