user1190420 user1190420 - 5 months ago 23
JSON Question

Rails 4 Custom Error Handling for Specific ContentTypes

I'm writing an API-only application using Rails 4.

The ActionControllers render templates specific to certain content types (like .html and .json)

So my question is, can I return custom errors (404, 500 etc.) specific to certain content-types sent in the request (e.g. Content-Type : application/json)?

Rails otherwise sends default 404.html, which doesn't work well with clients expecting a JSON-encoded result.

Answer

Although your question is not directly clear, here's what I'd be looking at...

--

Error Handling

We handle custom error pages using the config.exceptions_app middleware hook

We've written a gem for it called exception_handler & have a popular answer here. There's also a great github gist here

I would recommend using the exceptions_app middleware hook, with an accompanying controller to capture & respond to the errors:

# config/environments/development.rb
config.consider_all_requests_local = false # true -> for testing

#config/application.rb
config.exceptions_app = ->(env) { ExceptionController.action(:show).call(env) }

#app/controllers/exception_controller.rb
Class ExceptionController < ApplicationController
   respond_to :js, :json, :html

   def show
        @exception       = env['action_dispatch.exception']
        @status_code     = ActionDispatch::ExceptionWrapper.new(env, @exception).status_code
        @rescue_response = ActionDispatch::ExceptionWrapper.rescue_responses[@exception.class.name]
        respond_with @rescue_response
   end

end

This will allow you to create the custom pages you need, as well as being able to return the required mime types

--

respond_to

As a general rule, Rails allows you to use the respond_to code block to deliver different responses to different mime types

You can use the block in two ways:

#app/controllers/your_controller.rb
Class YourController < ApplicationController
   def your_action
      respond_to do |format|
         format.json
         format.html
      end
   end
end

Alternatively, you can use the respond_to & respond_with methods in tandem:

#app/controllers/your_controller.rb
Class YourController < ApplicationController
   respond_to :js, :json, :html

   def your_action
      @your_variable = "test"
      respond_with @your_variable #-> responds with appropriate mime-type
   end

end

--

Responses

If you want to issue a JSON-only response, you need to use all of the above code to create a controller which allows you to pass the JSON response.

You must remember that JSON responses are just a type of data response -- specifically, just providing a nested hash of all the data you respond with.

If you want to receive a JSON response to your errors, you basically need to be able to create a controller to handle the correct mime-type. What I've recommended above will do that for you