先日、Laravel5.5がリリースされました。
このバージョンは新しいLTSとなりますので、5.1からのアップグレードなどを検討してみましょう!
5.5で追加された仕組みの一つに、Eloquent: API Resourcesがあります。
以前からEloquentで取得したオブジェクトを直接レスポンスに与えると、
jsonで返却する機能がありました。
追加されたこの仕組みは、レスポンスとEloquentとの橋渡しをする機能となります。
便利な機能ではありますが、
データベースとの接続、データ返却を行うEloquentと、Httpのレスポンスが結び付き合うのは、
利便性という以外では責務が多すぎるため、
議論の的になることもあります。
と、マニュアルだけでは確かにそう見える機能ですが、
RESTでおなじみのLevel 3 - Hypermedia Controlsに対応することができます。
Eloquentを利用すれば、Resourceクラスがjsonに変換する際に、
meta情報などを付け加えることができます。
このレスポンスはjsonapiと呼ばれるフォーマットに近しい形で出力されます。
JSON API — A specification for building APIs in JSON
実際のアプリケーションではEloquent以外のものを利用することも多くあると思います。
本エントリでは、Eloquent以外のものでこのResourceを使って、
HALを適用します。
Resourceクラスは、 \Illuminate\Http\Resources\Json\Resource
を利用することで、
さまざまなフォーマットに沿ったjsonを定義することができます。
このResourceクラスには、型宣言がありませんが、toArrayメソッドを持つものであれば、
変換に利用することができます。
シンプルな配列を利用する場合は、次のようになるでしょう
<?php $embedded = new \Illuminate\Http\Resources\Json\Resource( new class implements \Illuminate\Contracts\Support\Arrayable { public function toArray() { return [ [ 'message' => 'hello', 'type' => 'example', '_links' => [ 'self' => 'http://example.com/1', 'hoge' => 'http://example.com/hoge/1', ], ], [ 'message' => 'hello', 'type' => 'example', '_links' => [ 'self' => 'http://example.com/2', 'hoge' => 'http://example.com/hoge/2', ], ], ]; } } );
このリソース一つ一つにナビゲート可能なリンクがあるものとして、記述しています。
ResourceCollectionクラスを利用することもありますが、
Collectionクラスに依存するため、今回は通常の配列のみを利用します。
このままレスポンスとして利用することも可能ですが、
このリソースを他のリソースで利用し、埋め込み情報として利用します。
<?php $resource = new \Illuminate\Http\Resources\Json\Resource( new class($embedded) implements \Illuminate\Contracts\Support\Arrayable { /** @var \Illuminate\Http\Resources\Json\Resource */ protected $resource; /** * constructor. * * @param \Illuminate\Http\Resources\Json\Resource $resource */ public function __construct(\Illuminate\Http\Resources\Json\Resource $resource) { $this->resource = $resource; } public function toArray() { return [ 'title' => 'illuminate/http resource', '_links' => [ 'self' => 'http://google.com', ], '_embedded' => $this->resource->jsonSerialize(), ]; } } ); $resource::$wrap = null;
最初に記述したリソースを埋め込み情報として利用するリソースクラスを作成します。
デフォルトでdataの配列となりますが、静的プロパティの$wrapに任意の名称を与えることができますので、
ここでは利用しないためnullとします。
埋め込み情報は _embedded
として利用します
最後にcontent-typeを 'application/hal+json'
としてレスポンスを返却するようにします。
<?php $response = $resource->response()->header('content-type', 'application/hal+json'); return $response;
レスポンスとしては次のように返却されます。
親子関係がはっきりしたデータ構造や実装であれば、
比較的ライトに実装することができると思います。
LaravelでEntityなどを表現して、データマッパーライクな実装をしている場合は、
以前のエントリを参考にアノテーションを使う実装の方が、
フィットするかと思います。