When a request crashes with an exception, you may want to handle it in a graceful manner. To do this, you can use handle_exception in your actions.

Actions do not handle exceptions raised by your application by default. To handle exceptions, you need to define how a specific exception type should be translated into an HTTP response.

An exception handler can be a HTTP status code (eg. 500, 401), or a symbol that represents a method on the action.

Status codes

  1. # app/actions/books/index.rb
  2. module Bookshelf
  3. module Actions
  4. module Books
  5. class Index < Bookshelf::Action
  6. handle_exception StandardError => 500
  7. def handle(request, response)
  8. raise "error"
  9. end
  10. end
  11. end
  12. end
  13. end

In the above action, when StandardError is raised in the #handle method, a basic 500 Internal Server Error will be returned.

Default error response

Custom method handlers

To do more with an exception than simply rendering a particular status code, call a method by providing a symbol with the method’s name:

  1. module Bookshelf
  2. module Actions
  3. module Books
  4. class Index < Bookshelf::Action
  5. handle_exception RecordNotFound => 404
  6. handle_exception StandardError => :handle_standard_error
  7. def handle(*, response)
  8. raise "error"
  9. end
  10. private
  11. def handle_standard_error(request, response, exception)
  12. response.status = 500
  13. response.format = :json
  14. response.body = {error: "Sorry, something went wrong handling your request"}.to_json
  15. end
  16. end
  17. end
  18. end
  19. end

Here, when StandardError is raised, #handle_standard_error will prepare a JSON response.

Methods used for exception handling accept three arguments: the request, the response and the exception being handled.

Handling exceptions in base actions

Rather than configure exception handling in every action, it’s usually convenient to configure it once, either in your app’s base action, or in the base action of a slice.

If you use an error reporting service like Bugsnag or Sentry, you can report on exceptions here too.

  1. # app/action.rb
  2. require "hanami/action"
  3. module Bookshelf
  4. class Action < Hanami::Action
  5. include Deps["sentry"]
  6. handle_exception StandardError => :handle_standard_error
  7. private
  8. def handle_standard_error(request, response, exception)
  9. sentry.capture_exception(exception)
  10. response.status = 500
  11. response.body = "Sorry, something went wrong handling your request"
  12. end
  13. end
  14. end

In development, where seeing a stack trace can be useful, reraise exceptions in order to make them visible in your browser.

  1. def handle_standard_error(request, response, exception)
  2. if Hanami.env?(:development)
  3. raise exception
  4. else
  5. response.status = 500
  6. response.body = "Sorry, something went wrong handling your request"
  7. end
  8. end