Lumen のjsonレスポンスを拡張する


Laravelではレスポンスマクロというものがある。

いろいろなルートやコントローラで、再利用するためのカスタムレスポンスを定義したい場合はResponseファサードのmacroメソッドが使用できます。

しかしLumenで試すとエラーが出る。そんなものなどないらしい。

Uncaught BadMethodCallException: Method error does not exist. in /var/www/html/src/vendor/illuminate/support/Traits/Macroable.php:74

この記事にかいてある通りResponseファサードがLaravelとは違うみたいですね。

Responseファサードがありません。
Responseファサードのクラス自体はあるのですが、getFacadeAccessor()が返すResponseFactoryContractクラスがDIコンテナに登録されていないので使えません。

けどなんとか拡張したいので下記のようにresponseヘルパーのjsonメソッドを追ってみる。
/vendor/laravel/lumen-framework/src/Http/ResponseFactory.php
→ /vendor/illuminate/http/JsonResponse.php

お、何かMacroableトレイトを使てるっぽい。JsonResponseに追加すればよさそう。

/vendor/illuminate/http/JsonResponse.php
class JsonResponse extends BaseJsonResponse
{
    use ResponseTrait, Macroable {
        Macroable::__call as macroCall;
    }

試す

サービスプロバイダを作成

app/Providers/ResponseMacroServiceProvider.php
    public function boot()
    {
        JsonResponse::macro('success', function ($data) {
            $rows = [
                'message' => 'success',
                'option_params' => '',
                'data' => $data,
            ];
            return JsonResponse::create($rows);
        });
    }

    public function register()
    {

サービスプロバイダーを登録。

bootstrap/app.php
$app->register(App\Providers\ResponseMacroServiceProvider::class);

あとはルーティングやコントローラーを追加する。

app/Http/Controllers/BlogContloer.php
    /**
     * ブログ一覧取得
     * @return JsonResponse
     */
    public function getBlogList(): JsonResponse
    {
        $data = [
            'id' => 1,
            'title' => '楽しいゆるふわPHPer'
        ];
        return JsonResponse::success($data);
    }

curlで確認。

curl -s "http://localhost:8080/api/blog" | jq

{
  "message": "success",
  "option_params": "",
  "data": {
    "id": 1,
    "title": "楽しいゆるふわPHPer"
  }
}

まとめ

Lumenにはレスポンスマクロはない。しかし、再利用するためのカスタムレスポンスを定義したい場合はJsonResponseクラスのmacroメソッドが使用できるよって話。(MacroトレイトをuseしてるならResponseクラスとかでもできる)
クライアントによってはjsonを共通ヘッダーパターンに変更する場合も使ってます。

(参考)
https://qiita.com/crhg/items/2ca642904955a2846de7