Ruegen
Ruegen

Reputation: 665

rails 5 api app with json error response instead of html error response

If I create an app in rails using the --api flag my error responses are in html rather than json.

How am I able to change the default error handler so that whenever an error is thrown in a controller action, I receive a json only response with the error and http status?

right now I am using the code below in every custom action

rescue => e
    response.status = 422
    render json: { error: e.message }

I'd rather not have to add this each time...

UPDATE: I used the rescue_from method in the application controller

rescue_from Exception do |exception|
    render json: exception, status: 500
end

But I feel this is very wrong and the status will always be hard coded as 500

Upvotes: 5

Views: 9107

Answers (2)

James Stonehill
James Stonehill

Reputation: 1212

You can use the api_error_handler gem.

Include it in your bundler file:

gem "api_error_handler", "~> 0.2.0"

The in your application controller, invoke the library.

class ApplicationController < ActionController::API
  handle_api_errors(
    # Error handling options go here if you want to override any defaults.
  )

  # ...
end

Now if you have a controller like this:


class UsersController < ApplicationController
  def index
    raise 'SOMETHING WENT WRONG!!!'
  end
end

When you hit this endpoint you will see this response

{
  "error": {
    "title": "Internal Server Error",
    "detail": "SOMETHING WENT WRONG!!!"
  }
}

And the status code will be set to an appropriate status code based on the type of error you had.

See the gem's README for more info on how to configure the error response.

Upvotes: 0

Vishal
Vishal

Reputation: 7361

you can add format as json in routes so it will always accept request in json format like below

namespace :api, as: nil, defaults: { format: :json } do
     devise_for :users, controllers: {
        registrations: "api/v1/users/registrations",
        passwords: "api/v1/users/passwords"
      }

      resources :products, only: [:show,:index] do
        get "check_product_avaibility"
        get "filter", on: :collection
      end
end

For handling errors globally, you can add around_action in application controller file

around_action :handle_exceptions, if: proc { request.path.include?('/api') }

# Catch exception and return JSON-formatted error
  def handle_exceptions
    begin
      yield
    rescue ActiveRecord::RecordNotFound => e
      @status = 404
      @message = 'Record not found'
    rescue ActiveRecord::RecordInvalid => e
      render_unprocessable_entity_response(e.record) && return
    rescue ArgumentError => e
      @status = 400
    rescue StandardError => e
      @status = 500
    end
    json_response({ success: false, message: @message || e.class.to_s, errors: [{ detail: e.message }] }, @status) unless e.class == NilClass
  end

NOTE: render_unprocessable_entity_response and json_response are custom methods , you can add your own methods to render json response.

Upvotes: 6

Related Questions