LoginSignup
7
11

More than 5 years have passed since last update.

LaravelのJSON出力をPrettyPrintしたかった

Last updated at Posted at 2019-01-22

Laravelのコントローラは、配列を返せば勝手にJSONにして表示してくれます。
ここをPrettyPrintしたかったのでIlluminate\Http\Responseを覗いてみたのですが、

Response疑似コード
public function setContent($content)
    if ($this->shouldBeJson($content)) {
        $this->header('Content-Type', 'application/json');
        if ($content instanceof Jsonable) {
            return $content->toJson();
        } elseif ($content instanceof Arrayable) {
            return json_encode($content->toArray());
        }
        return json_encode($content);
    }
}

とかなってて手を出せませんでした。

公式の過去議論を漁ってみたところ、『そんなものはいらん』『自分でResponse::json()って書け』みたいなかんじになってました。

もっとよい答えはないか探していたところ、そのあたりミドルウェアで作った人を見つけました。
以下はAaron Sarayによるブログ記事、Laravel Pretty Print JSON Middlewareの日本語訳です。

Laravel Pretty Print JSON Middleware

私はテストをするためにPostmanをよく使います。
これはプレビューモードにおいて、APIのJSONレスポンスを整形・解読して表示してくれます。
しかし先日、外部ツールを使用したり環境全体を変更したりせず、ただ単にJSONレスポンスをPrettyPrintしたいだけの人がいるということを小耳に挟みました。

知ってのとおりjson_encodeはエンコードオプションに対応していて、そのうちのひとつがJSON_PRETTY_PRINTです。
これは改行とスペースを挿入し、整形されたJSONを出力するというオプションです。
私は現在Laravelのプロジェクトに取り組んでいるため、Laravelで同じことを行いたくなりました。
これを行うにはどうすればよいでしょうか?
簡単にできるちょっとしたソリューションですか?

最初に試した方法は、response()->json()のようにJSONで返しているところを全て探し出して、そこにオプションを追加する方法でした。
それは全くスケーラブルでなく、そしていとも簡単に見逃してしまいます。
そこで私はミドルウェアを使うことを思いつきました。

<?php
/**
 * クエリに'?pretty=true'と入れるとJSONがPrettyPrintで返ってくるミドルウェア
 */
declare(strict_types=1);

namespace App\Http\Middleware;

use Illuminate\Http\JsonResponse;

/**
 * Class PrettyPrintMiddleware
 * @package App\Http\Middleware
 */
class PrettyPrintMiddleware
{
  /**
   * @var string 監視対象のクエリパラメータ
   */
  const QUERY_PARAMETER = 'pretty';

  /**
   * 指定があればJSON_PRETTY_PRINTして返す
   * 
   * @param $request
   * @param \Closure $next
   * @return mixed
   */
  public function handle($request, \Closure $next)
  {
    $response = $next($request);

    if ($response instanceof JsonResponse) {
      if ($request->query(self::QUERY_PARAMETER) == 'true') {
        $response->setEncodingOptions(JSON_PRETTY_PRINT);
      }
    }

    return $response;
  }
}

このミドルウェアを割り当てたのち、クエリパラメータpretty=true (QUERY_PARAMETERで他の値に変更可能) を指定するとレスポンスにエンコードオプションが追加されます。
他には何もする必要なく、あなたの要求を満足するでしょう。

通常のJSONはこのようになります。

[{"id":123,"name":"first item"},{"id":124,"name":"first item"}]

今後はこうなります。

[
    {
        "id": 123,
        "name": "first item"
    },
    {
        "id": 123,
        "name": "first item"
    }
]

念頭に置いておくべきことは、これは非常に巨大な破壊的アプローチであるということです。
もし他のJSONエンコードオプションを使用している場合は、単に設定するだけではなく、設定をスタックに積む必要があります。

このコードをパッケージ化する場合は、パラメータのqueryをコンフィグで設定するようにするとよいでしょう。
また、値にも1TRUEonなども受け付けるようにするとよいでしょう。

感想

アクションごと個別にPrettyPrintしたいのであれば、

  return response()->json($output, 200, [], \JSON_PRETTY_PRINT);

で事足ります。

しかし、全てのJSONレスポンスに対して一括でPrettyPrintしたい場合、全てのreturn部分を書き換えるとか、ResponseクラスをextendsしてsetContentを書き換えるとか、そういうのはちょっとやりたくない方法です。
そんな場合はこのミドルウェアが役立ちますね。

なお記事にもあるとおり、この書き方では既に他のオプションが設定されていた場合、それが消えてしまいます。
該当部分を以下のように書き換えるとよいでしょう。

  $response->setEncodingOptions($response->getEncodingOptions() | JSON_PRETTY_PRINT);

JSON_PRETTY_PRINTで全く日本語記事が見当たらなかったのでここまで苦労して調べたのですが、JSON_UNESCAPED_UNICODEだと山ほど見つかったとかいう。

7
11
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
11