Ruby on RailsのJSONレスポンスをprettifyする3つの方法

モチベーション

翻訳: WebAPI 設計のベストプラクティス - Qiita

JSON はデフォルトで整形しよう
圧縮された状態の JSON をブラウザ上で見るのは、決して気持ちの良いものではありません

手段

大きく分けて3つの方法があります。

  1. 共通メソッドを用意する
  2. Rack Middlewareを使う
  3. Rendererを追加する

それぞれメリットとデメリットがあります。

共通メソッドを用意する

使い方

コントローラーの各メソッドでrender json:の代わりに呼び出します。

class ExampleController < ActionController
  def show
    pretty_json { key: 'value' }
  end
end

実装方法

ApplicationControllerなどに共通メソッドを用意します。

class ApplicationController < ActionController
  def pretty_json(obj, options = nil)
    render json: JSON.pretty_generate(obj.as_json(options))
  end
end

json rendererは文字列を渡されると、文字列化をスキップします。

json = json.to_json(options) unless json.kind_of?(String)

JSON.pretty_generateで変換した、prettyなJSON文字列を渡します。

as_jsonの補足

as_jsonメソッドを呼ぶのは、ハッシュ以外のオブジェクト(ActiveRecordのインスタンスなど)をハッシュに変換するためです。to_jsonメソッドを呼ぶとJSON文字列に変換されます。rails consoleで試すと

irb(main):017:0> true.as_json
=> true
irb(main):018:0> true.to_json
=> "true"

as_jsonは真理値を返しますが、to_jsonは文字列に変換します。
このため、to_jsonした値を、JSON.pretty_generateに渡すと、ダブルクォートが二重になります。

irb(main):019:0> JSON.pretty_generate true.as_json
=> "true"
irb(main):020:0> JSON.pretty_generate true.to_json
=> "\"true\""

デメリット

  • 見た目がrender json: objと変わり、美しくない
  • 主な関心ごとでないソースコードが、アプリケーションのソースコードに混ざる
  • メソッド単位での変更が必要

メリット

  • 実装がわかりやすい

Rack Middlewareを使う

使い方

config/environments/development.rbに、次のように記述します。

config.middleware.use PrettyJsonResponse

実装方法

2012年のHow can I "pretty" format my JSON output in Ruby on Rails? - Stack Overflowにある、伝統的な手法です。

次のようなRack Middlewareを作ります。

class PrettyJsonResponse
  def initialize(app)
    @app = app
  end

  def call(env)
    status, headers, response = @app.call(env)
    if headers["Content-Type"] =~ /^application\/json/
      obj = JSON.parse(response.body)
      pretty_str = JSON.pretty_unparse(obj)
      response = [pretty_str]
      headers["Content-Length"] = pretty_str.bytesize.to_s
    end
    [status, headers, response]
  end
end

Gem rails_pretty_jsonを作っている人がいるので、使う場合は自作せずに、Gemを使うとよいでしょう。

デメリット

  • 環境ごとに設定が必要
  • Railsが一度JSON文字列にしたものを、Rack Middlewareでパースしてオブジェクトにしてから、再度JSON文字列に戻す

後者がパフォーマンス的にどれぐらいの影響があるかはわかりません。何となく気持ち悪いです。

メリット

  • 環境ごとに設定できる
  • 全てのレスポンスを一括で変更できる

「development環境は設定し、productionは設定しない」というような使い方に向いています。

Rendererを追加する

使い方

コントローラーのメソッドで、他のrendererと同様に呼び出します。

class ExampleController < ActionController
  def show
    render pretty_json: { key: 'value' }
  end
end

実装方法

config/initializers/application_controller_renderer.rb

ActionController::Renderers.add :pretty_json do |obj, options|
  _render_with_renderer_json JSON.pretty_generate(obj.as_json(options)), options
end

を追加します。
_render_with_renderer_jsonは、render json:した時に実行されるメソッドです。
処理の内容は「共通メソッドを用意する」と同じです。

これもGem rails_pretty_json_rednererを作っている人がいるので、使う場合は自作せずに、Gemを使うとよいでしょう。

デメリット

  • メソッド単位での変更が必要

メリット

  • 見た目がrender json: objに似ていて、かっこいい
Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account log in.