モチベーション
翻訳: WebAPI 設計のベストプラクティス - Qiita
JSON はデフォルトで整形しよう
圧縮された状態の JSON をブラウザ上で見るのは、決して気持ちの良いものではありません
手段
大きく分けて3つの方法があります。
- 共通メソッドを用意する
- Rack Middlewareを使う
- Rendererを追加する
それぞれメリットとデメリットがあります。
サマリ
方法 | メリット | デメリット |
---|---|---|
共通メソッドを用意する | 実装がわかりやすい |
|
Rack Middlewareを使う | 環境ごとに設定できる 全てのレスポンスを一括で変更できる |
|
Rendererを追加する | 見た目がrender json: objに似ていて、かっこいい | メソッド単位での変更が必要 |
共通メソッドを用意する
使い方
コントローラーの各メソッドで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
に似ていて、かっこいい