Rails

gem 'restful_error' をリリースしました

More than 3 years have passed since last update.

シングルページアプリケーションを書く時にいっつも似たようなコードを書いていたので、勢い余って gem にしました。


使い方


Gemfile

gem 'restful_error'


って書いて、


application_controller.rb

class ApplicationController < ActionController::Base

include RestfulError::ActionController


って書いておく。

そうすると、

def show

@post = Post.find(param[:id])
end

みたいなアクションがあったとして、 GET /posts/10.json すると

{ status_code: 404, message: "要求されたリソースが存在しません"}

みたいに json がちゃんと返ってくる。(もちろん status code は404)

他のステータスも自由に raise できる。

class PostsController < ApplicationController

before_action do
raise RestfulError[401] unless current_user
# or
raise RestfulError::Unauthorized unless current_user
end
end

自分でエラーを定義する時は、継承するか

class ::NoSession < RestfulError[404]; end

# or
class ::NoSession < RestfulError::NotFound; end

status_code メソッドを定義しておく (duck typing)

class OAuthController < ApplicationController

# all you need is status_code
class RequireTwitterLogin < StandardError
def status_code; 401; end
end
# or
class RequireTwitterLogin < StandardError
def status_code; :unauthorized; end
end
end


response のカスタマイズ

デフォルトで、 html, json, xml に応答する。

message のとこは


config/locales/restful_error.yml

ja:

restful_error:
active_record/record_not_found: 要求されたリソースが存在しません
not_found: ページが存在しません

で設定可能。

active_record/record_not_foundActiveRecord::RecordNotFound 専用、 not_found は 404 エラー汎用となる。

status_message というメソッドがある場合にはそれを優先する。

class RequireLogin < StandardError

def initialize(provider = 'Unknown')
@provider = provider
end
def status_code
:unauthorized
end
def status_message
I18n.t('restful_errors.require_login', provider: provider)
end
end

以下のいずれかを置いておけば、レスポンスを柔軟にカスタマイズ出来る。


  • views/restful_error/show.html.erb

  • views/restful_error/show.json.jbuilder

  • views/restful_error/show.xml.erb

(もちろん haml でも rabl でもそこはご自由に)


中身の話

ActiveRecord::RecordNotFound が raise された時にステータスコードがちゃんと 404 になる仕組みが Rails にもともとあって、これは config/application.rb とかで

config.action_dispatch.rescue_responses.merge!(

'MyGreatError' => :not_found,

としておくと、 raise MyGreatError で 404 を返してくれる。

resutful_error は rescue_responses に値を追加しないが、既に追加されているものについては参照している。なので、 ActiveRecord::RecordNotFound ではちゃんと 404 になるし、 ActiveRecord::RecordInvalid ではちゃんと 422 になる。

ステータスコードのリストみたいなのどっかにないかなーと思ったら標準ライブラリの webrick の中に綺麗に定義されてた。

https://github.com/ruby/ruby/blob/trunk/lib/webrick/httpstatus.rb

これ、 Webrick の中に入っちゃってるのもったいないなーと思い、引っ張りだして使っています。

全てのステータスコードにシンボルが対応していて、数字でもシンボルでもどっちでも使えるようになっている。便利。

例外には message メソッドがあるのだけどこれは i18n に対応していないので使用しない。クラス名、 reason phrase (404 なら not_found みたいなやつ) の順に i18n のキーを検索して適用することにしている。

開発の邪魔にならないように、(config.consider_all_requests_local = true) の場合 status_code が 500 のエラーは処理せず raise している。


FAQ


どこがrestfulやねん

すいません、誇大広告です。

いちおう気持ちとしては、'RESTってhttpのURLとかメソッドとかを、ちゃんと本来の意味で使おうね' っていう運動だと理解しており、適切なステータスコードで結果を返すのもその方向性だろうと思って、この名前にしています。


ツッコミをお待ちしております

https://github.com/kuboon/restful_error