Rails にJSONでリクエストを投げた際に発生する JSON::ParserError をハンドリングする

何が問題か

API として公開している Rails Server に対して、Invalid な JSON データを送信した場合、 parse error が発生した場合は、適切にリダイレクトやエラーメッセージの制御を行いたい。

だけど、挙動としては、Controller に到達する前の Rack Layer で勝手に parse 処理が走ってしまい、 Rack Layer で raise されて勝手に落ちてしまう。

具体的には ActionDispatch::ParamsParserが先にパラメータを見ている。

吐かれるログはこんな感じ

Started PUT "/api/users/5001" for ::1 at 2016-07-07 16:24:16 +0900
Error occurred while parsing request parameters.
Contents:

{
  "user": {
    "email": "sample@example.com",
    "password": "cGFzc3dvcmQ=",
    "name": "田中太郎"
  }
}:
  /.rbenv/versions/2.3.1/lib/ruby/2.3.0/json/common.rb:156:in `parse'
  activesupport (4.2.4) lib/active_support/json/decoding.rb:26:in `decode'
  actionpack (4.2.4) lib/action_dispatch/middleware/params_parser.rb:44:in `parse_formatted_parameters'

ログに生情報がそのまま出てしまうし、リクエスト元にも同じ内容が返ってしまう。 さらに、リダイレクトやエラーメッセージの表示を制御できないのもマズい。

どうすればいいのか

middleware のスタックに、ActionDispatch::ParamsParser  よりも前にハンドリング用の middleware を差し込む。

今回自分は Committeeという Gem を使っていて、この Gem で定義されている ハンドリング処理に任せたかったので、

application.rb では以下のように指定した

config.middleware.insert_before ActionDispatch::ParamsParser, Committee::Middleware::RequestValidation, schema: JSON.parse(File.read(schema_file))

config.middleware.insert_before ActionDispatch::ParamsParser, Committee::Middleware::ResponseValidation, schema: JSON.parse(File.read(schema_file))

参考