Railsでrescue_fromを使ってエラー処理を共通化する
Railsのコントローラクラスのrescue_fromメソッドは、例外が発生した場合に実行するメソッドを指定できます。
コントローラーで独自のエラページをエラー内容によって切り替えたり、
APIでエラーが発生した場合に処理を共通化する場合などrescue_fromメソッドを使うとスッキリします。
ということで、APIのエラー処理の共通化を考えてみます。
各APIコントローラーのスーパークラス
各APIコントローラのスーパークラスを作成し、サブクラスで発生した例外は全てここでハンドリングします。
Api::TuleApiErrorが発生した場合、Api::ApiControllerのtule_api_errorメソッドが実行されます。
下記の例ではトークンが不正な場合は、HTTPステータスを401 Unauthorized、それ以外の場合は200 OKを返しています。
HTTPステータスは、例外の内容によって適切な値を設定します。
class Api::ApiController < ActionController::API
include ActionController::HttpAuthentication::Token::ControllerMethods
rescue_from Api::TuleApiError, with: :tule_api_error
protected
# トークン認証
def authenticate
・
・
・
end
private
# エラー時のレスポンスを返す
def tule_api_error(e)
header = {result: e.code, message: e.message}
response = {header: header}
status = :ok
status = :unauthorized if e.code == Api::Result::HTTP_TOKEN_ACCESS_DENIED
render json: response, status: status
end
end
上記のコードでApi::Resultはエラーコードを定義しているクラスです。
APIの例外クラス
APIの例外クラスはStandardErrorを継承します。
class Api::TuleApiError < StandardError
attr_accessor :code
def initialize(code, message_id)
self.code = code
super(I18n.t(message_id, locale: :ja))
end
end
各APIコントローラーはApi::ApiControllerを継承し処理中にエラーが発生した場合に例外を発生させます。
下記の例ではリクエストの中に期限がなかった場合にApi::TuleApiErrorを発生しています。
Api::TuleApiErrorが発生するとApi::ApiControllerのtule_api_errorメソッドが実行され
クライアントにエラーコードとメッセージをレスポンスとして返します。
APIコントローラーの例
class Api::V1::TargetsController < Api::ApiController
before_action :authenticate
# 目標を登録
def create
# リクエストから目標のデータを取得
body = request.body.read
req = ActiveSupport::JSON.decode(body)
attrs = request_to_target(req)
# 期限が未入力
raise Api::TuleApiError.new(Api::Result::PLEASE_ENTER_DEADLINE, 'api.error.target.please_enter_deadline') if attrs[:time_limit].nil?
attrs[:user_id] = @login_user.id
@target = Target.create(attrs)
@header = Api::ResponseHeader.new(Api::Result::OK)
end
・
・
・
・
end
このようにエラー時の処理を一箇所にまとめることでコードがスッキリします。