環境
Ruby 2.5.7
Rails 5.2 (ActionPack 5.2)
コード
lib/middleware/routing_error_response_json.rb
module YourNameSpace::Middleware
class RoutingErrorResponseJson
RESPONSE_JSON_PATHS = %w[/api/v1]
def initialize(app)
@app = app
end
def call(env)
request = ActionDispatch::Request.new(env)
status, headers, response = @app.call(env)
# NOTE: ActionController::RoutingError時に設定されるパラメータ
# See https://github.com/rails/rails/blob/5-2-stable/actionpack/lib/action_dispatch/journey/router.rb#L64
if enable?(request) && status == 404 && headers['X-Cascade'] == 'pass'
status, headers, response = pass_response(status)
end
[status, headers, response]
rescue Exception => exception # rubocop:disable Lint/RescueException
raise exception
end
private
def pass_response(status)
[
status,
{ "Content-Type" => "application/json" },
[
JSON.generate(
{
title: 'Routing Error',
detail: 'No route matches',
invalid_params: []
}
)
]
]
end
def enable?(request)
RESPONSE_JSON_PATHS.any? { |path| request.path.to_s.start_with?(path) }
end
end
end
config/initializers/middleware.rb
require_relative "../../lib/middleware/routing_error_response_json"
::Rails.application.config.middleware.use YourNameSpace::Middleware::RoutingErrorResponseJson
実現できる事
↑の例であれば /api/v1
以下へのリクエストでRoutingErrorとなった場合にJSONを返却する事ができる。
WebとApiが同居しているアプリケーションなどで利用価値があるかもしれない。
最後に
もっと良い方法があれば教えて欲しいです。