KatPadi's Point

Handling Global Exceptions for APIs

I was able to teach myself (this includes a lot of Google-ing and asking) how to do some basic exceptions handling in a Rails app that uses GrapeAPI. I’ve experimented with Sinatra before for a hackathon so I was a little familiar with some of the concepts already but there are still things to learn (a lot actually!). The thing that “amazed” me with Grape is its built-in support for versioning APIs out-of-the-box. Check it out here.

So why bother handling the exceptions? Well, I believe it’s basically for DRYing up things especially if these exceptions in general are happening very often in your API.

Anyway, so the first thing I learned was to extend ActiveSupport::Concern so that I’ll be able to use its “rescue_from” method in my API. This is assuming that the API is separated from the app itself. After doing so, I created a module and collected the usual exceptions that I encounter. For example:

  • ActiveRecord::RecordNotFound – usually when an HTTP “PUT” method is in place and there’s no record in the database
  • CanCan::AccessDenied – for authorization issues
  • Grape::Exceptions::ValidationErrors – for all Grape validation exceptions such as required parameters, invalid parameters etc.

After identifying the “identifiable” exceptions (I’m not sure if one can actually determine everything), I wrote down the famous rescue_from :all code for a graceful exit.

module API
  module V1
    module ExceptionsHandler
      extend ActiveSupport::Concern
    
      included do
        rescue_from ActiveRecord::RecordNotFound do |e|
          error_response(message: e.message, status: 404)
        end
  
        rescue_from CanCan::AccessDenied do |e|
          error_response(message: e.message, status: 403)
        end
    
        # Example of a random exception
        rescue_from KatPadiService::Client::ParamoreException do
          error_response(message: 'You are not the exception', status: 501)
        end
    
        rescue_from Grape::Exceptions::ValidationErrors do |e|
          error_response(message: e.message, status: 406)
        end
    
        # When all else fails...
        rescue_from :all do |e|
          Rails.logger.error "\n#{e.class.name} (#{e.message}):"
          e.backtrace.each { |line| Rails.logger.error line }
          error_response(message: 'Internal server error', status: 500)
        end
      end
    end
  end
end

My module is just a basic implementation of exception handling in a Rails API but it serves its purpose so I’m a happy coder right now.

1 comment for “Handling Global Exceptions for APIs

Leave a Reply

Your email address will not be published. Required fields are marked *