Error Response is a json response gem to help you easily manage all your custom error statuses in your Rails application.
Add error_response to your Rails application's Gemfile.
gem 'error_response'And then install the gem.
$ bundle installCreate your response config in config/error_response.yml.
# config/error_response.yml
source:
local:
- your/local/file_1.yml
- your/local/file_2.yml
remote:
- https://your_remote_file_1.yml
- https://your_remote_file_2.ymlThe error_response gem looks up all yml files and merge them into a hash.
You can also customize your config file path through configuration.
ErrorResponse.configure do |config|
config.yaml_config_path = 'your/local/config/file.yml'
endYou can provide an extension hook to customize the message passed into ErrorResponse::Helper#error_response without monkey patching.
When error_response is called, the gem invokes ErrorResponse.resolve_error_message before building the API payload. The resolved value is then passed to ErrorResponse.to_api as the optional message suffix.
ErrorResponse.configure do |config|
config.error_message_resolver = lambda do |key:, error_message:, error_data:, context:|
# Return a string message, nil, or any value accepted by `to_api`.
# context is the current controller instance when called from helper.
"customized message for #{key}"
end
end| Argument | Description |
|---|---|
key |
The error key passed to error_response (e.g. :bad_request_1). |
error_message |
The optional custom message passed to error_response. |
error_data |
The optional hash or array passed to error_response. |
context |
The current controller instance when called from ErrorResponse::Helper. nil when calling ErrorResponse.resolve_error_message directly. |
- Return a
Stringto append after the YAML-defined message (e.g."bad request 1: customized message for bad_request_1"). - Return
nilto keep only the YAML-defined message (no suffix is appended). - If the resolver is not configured, does not respond to
call, or raises an exception, the originalerror_messageis used as a safe fallback.
Keyword arguments (recommended):
config.error_message_resolver = lambda do |key:, error_message:, error_data:, context:|
error_message
endPositional arguments (backward compatible):
config.error_message_resolver = lambda do |key, error_message, error_data, context|
error_message
end**kwargs style:
config.error_message_resolver = lambda do |**kwargs|
kwargs[:error_message]
endMethod object:
class ErrorMessageResolver
def call(key:, error_message:, error_data:, context:)
error_message
end
end
ErrorResponse.configure do |config|
config.error_message_resolver = ErrorMessageResolver.new
endGiven this resolver:
ErrorResponse.configure do |config|
config.error_message_resolver = lambda do |key:, error_message:, error_data:, context:|
data = error_data.is_a?(Hash) ? error_data : {}
I18n.t("errors.#{key}", default: error_message, **data)
end
endCalling error_response(:bad_request_1, 'no required data', { a: 1 }) produces:
{
"error_code": 400001,
"error_message": "bad request 1: no required data",
"error_key": "bad_request_1",
"a": 1
}The resolver can rewrite error_message before it is appended. error_data is merged into the JSON response after message resolution and is not modified by the resolver.
Include helpers in your base application controller.
# in controller
class Api::ApplicationController < ActionController::Base
include ErrorResponse::Helper
...
endThe success response is used when the request is success. The response body is a hash with a data key.
# in controller actions
data = { a: 1, b: 2 }
return success_response(data) if success?response status: 200
response body:
{
"data": {
"a": 1,
"b": 2
}
}The error response is used when the request is not valid. Therefore, you need to provide the error_key defined in the config files.
# in controller actions
return error_response(:bad_request_1) if failed?response status: 400
response body:
{
"error_code": 400001,
"error_message": "bad request 1",
"error_key": "bad_request_1"
}You can also provide your custom error message and error data. If error data is a hash, it will be merged into the json response; If it is an array, it will be merged into the json response with an error_data key.
When config.error_message_resolver is configured, the custom message is passed through the resolver before being appended to the YAML-defined message. See Error Message Resolver for details.
# in controller actions
return error_response(:bad_request_1, 'no required data', { a: 1, b: 2 }) if failed?response status: 400
response body:
{
"error_code": 400001,
"error_message": "bad request 1: no required data",
"error_key": "bad_request_1",
"a": 1,
"b": 2
}If you do not want to handle the response in controllers, you can just raise an ErrorResponse::RequestError exception. The gem catches the exception in the base application controller and renders error_response.
ErrorResponse::Helper handles RequestError through rescue_with_handler before falling back to Rails generic rescue handlers. This guarantees that ErrorResponse::RequestError is rendered by error_response, even when the controller defines broad handlers such as rescue_from Exception.
Because of this priority guarantee, controller-level handlers such as rescue_from ErrorResponse::RequestError will not override the gem's RequestError handling after ErrorResponse::Helper is included. If you need custom messages or payloads, use ErrorResponse::RequestError arguments or configure config.error_message_resolver to customize the response.
flowchart TD
A[Raise ErrorResponse::RequestError] --> B[ErrorResponse::Helper#rescue_with_handler]
B --> C{Exception is RequestError?}
C -->|Yes| D[Build payload via error_response]
D --> E[Render structured error JSON]
C -->|No| F[Fallback to controller rescue_from handlers]
F --> G[Render controller-defined error response]
# in controller
class Api::ApplicationController < ActionController::Base
include ErrorResponse::Helper
# Broad handlers are still allowed and continue to work for other exceptions.
rescue_from Exception do |e|
Rails.logger.error(e.message)
render status: 500, json: { error: "unexpected error" }
end
end# in any business logic file
raise ErrorResponse::RequestError.new(:bad_request_1)See all available error_code & error_message
ErrorResponse.allReturn to hash only
ErrorResponse.to_hash(:bad_request_1)gives you
{
"error_code": 400001,
"error_message": "bad request 1",
"error_key": "bad_request_1"
}Resolve error message with optional resolver hook
ErrorResponse.resolve_error_message(
key: :bad_request_1,
error_message: "no required data",
error_data: { field: "email" },
context: controller # optional
)gives you the resolved message string (or the original error_message when no resolver is configured), for example:
"no required data"
If you would like to report a security issue, please review the Security Policy.
The gem is available as open source under the terms of the MIT License.