はじめに
初めての投稿となりますので間違い等ありましたらご指摘いただけると幸いです。
LaravelのAPIでreturnする時に
- json()で返す方法
- new UserCollectionの様に返す方法
上記の方法があるのは知っていたけど普段はMPA構成を作ることが多くあまり詳細について知らなかったので調べてみました。
結論
ざっくり以下の様な使い分けで良いのかなと思いました。
json()
- シンプルに返したい場合
- モデルと関係ない場合
- 外部APIのレスポンスを返す時
Resource,Collection
- モデルを返す時
- 複数箇所で一貫したレスポンスを返したい時
- データ整形をしたい時
- whenLoadedでN+1の回避 (記事内では割愛します
以下はサンプルです。
json()の場合
Route::get('/', function () {
// 第二引数にstatus codeを指定できる(defaultは200)
return response()->json(["user" => User::all()], 200]);
});
// return
[
{
"id": 1,
"name": "user1",
"email": "user1@user.com"
},
{
"id": 2,
"name": "user2",
"email": "user2@user.com"
}
]
Resource,Collectionの場合
準備
php artisan make:resource UserResource
でリソースファイルを作成
use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\JsonResource;
class UserResource extends JsonResource
{
public function toArray(Request $request): array
{
return parent::toArray($request);
}
}
toArrayをカスタムしてreturnする項目を変更できます。
// UserResource
public function toArray(Request $request): array
{
return [
'id' => $this->id,
'name' => $this->name,
'email' => $this->email,
// 必要に応じて、関連データや条件付きの属性を追加(割愛)
// 'posts' => PostResource::collection($this->whenLoaded('posts')),
];
}
呼び出し
Route::get('/', function () {
return new UserResource(User::find(1));
});
// return
{
"data": {
"id": 1,
"name": "user1",
"email": "user1@user.com"
}
}
dataキーでラップされて出力されます。dataをなくしたい場合はAppServiceProviderを以下の様にします。
// AppServiceProvider
public function boot()
{
JsonResource::withoutWrapping();
}
// return
{
"id": 1,
"name": "user1",
"email": "user1@user.com"
}
collectionについて
JsonResourceクラスによって提供されるcollectionメソッドを使用する事で以下の様にコレクションを返します。
Route::get('/', function () {
return UserResource::collection(User::all());
});
// return
{
"data": [
{
"id": 1,
"name": "user1",
"email": "user1@user.com"
},
{
"id": 2,
"name": "user2",
"email": "user2@user.com"
}
]
}
別途php artisan make:resource UserCollection
でリソースコレクションを返すクラスも生成できます。カスタムする場合は以下の様にします。
use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\ResourceCollection;
class UserCollection extends ResourceCollection
{
public function toArray($request)
{
return [
'data' => $this->collection,
'links' => [
'self' => 'link-value',
],
];
}
}
Route::get('/', function () {
return new UserCollection(User::all());
});
// return
{
"data": [
{
"id": 1,
"name": "user1",
"email": "user1@user.com"
},
{
"id": 2,
"name": "user2",
"email": "user2@user.com"
}
],
"links": {
"self": "link-value"
}
}
UserCollection内のtoArrayで配列の加工ができます。上記ではlinksキーを追加しています。
またUserResource,UserCollectionを用意してcollection内で$collectsをオーバーライドするとresourceと同じ内容を返すことができます。
// UserCollection
class UserCollection extends ResourceCollection
{
public $collects = UserResource::class;
public function toArray(Request $request): array
{
// ...
}
}
// UserResource
class UserResource extends JsonResource
{
public function toArray(Request $request): array
{
return [
'id' => $this->id,
'name' => $this->name,
];
}
}
Route::get('/', function () {
return new UserCollection(User::all());
});
// return
{
"data": [
{
"id": 1,
"name": "user1"
},
{
"id": 2,
"name": "user2"
}
],
"links": {
"self": "link-value"
}
}
あとがき
サンプルコードのが短く、似た様な結果になってしまい、某「全部同じじゃないですか」の様になってしまいましたが結論の所に書いた感じの使い分けで良いのかなと思いました。
今回の記事はlaravelドキュメントを見ていてサンプルコードはあるけど戻り値どうなるのか見られたら良いなと思い実際に動かしてコピペしました。
誰かの助けになれば幸いです。
(この記事はAIに壁打ちしながら作成したものとなります。)
参考