Help us understand the problem. What is going on with this article?

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

More than 1 year has passed since last update.

モチベーション

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

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

手段

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

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

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

サマリ

方法 メリット デメリット
共通メソッドを用意する 実装がわかりやすい
  1. 見た目がrender json: objと変わり、美しくない
  2. 主な関心ごとでないソースコードが、アプリケーションのソースコードに混ざる
  3. メソッド単位での変更が必要
    Rack Middlewareを使う 環境ごとに設定できる
    全てのレスポンスを一括で変更できる
    1. 環境ごとに設定が必要
    2. Railsが一度JSON文字列にしたものを、Rack Middlewareでパースしてオブジェクトにしてから、再度JSON文字列に戻す
    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に似ていて、かっこいい
    ledsun
    編集リクエスト、コメント大歓迎です。
    luxiar
    Ruby on Rails専門のWebアプリケーション開発に特化した町田の受託開発企業です
    http://www.luxiar.com/index.html
    Why not register and get more from Qiita?
    1. We will deliver articles that match you
      By following users and tags, you can catch up information on technical fields that you are interested in as a whole
    2. you can read useful information later efficiently
      By "stocking" the articles you like, you can search right away