Laravel APIのResource,Collectionとjson()について

## はじめに
初めての投稿となりますので間違い等ありましたらご指摘いただけると幸いです。

LaravelのAPIでreturnする時に
* json()で返す方法
* new UserCollectionの様に返す方法

上記の方法があるのは知っていたけど普段はMPA構成を作ることが多くあまり詳細について知らなかったので調べてみました。

## 結論
ざっくり以下の様な使い分けで良いのかなと思いました。
### json()
* シンプルに返したい場合
* モデルと関係ない場合
* 外部APIのレスポンスを返す時

### Resource,Collection
* モデルを返す時
* 複数箇所で一貫したレスポンスを返したい時
* データ整形をしたい時
* whenLoadedでN+1の回避 (記事内では割愛します

以下はサンプルです。
## json()の場合
```php
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``でリソースファイルを作成
```php
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する項目を変更できます。
```php
// UserResource
public function toArray(Request $request): array
{
    return [
        'id' => $this->id,
        'name' => $this->name,
        'email' => $this->email,
        // 必要に応じて、関連データや条件付きの属性を追加(割愛)
        // 'posts' => PostResource::collection($this->whenLoaded('posts')),
    ];
}
```
### 呼び出し
```php
Route::get('/', function () {
    return new UserResource(User::find(1));
});

// return
{
  "data": {
    "id": 1,
    "name": "user1",
    "email": "user1@user.com"
  }
}

```
dataキーでラップされて出力されます。dataをなくしたい場合はAppServiceProviderを以下の様にします。
```php
// AppServiceProvider
public function boot()
{
    JsonResource::withoutWrapping();
}

// return
{
  "id": 1,
  "name": "user1",
  "email": "user1@user.com"
}

```
### collectionについて
JsonResourceクラスによって提供されるcollectionメソッドを使用する事で以下の様にコレクションを返します。
```php
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``でリソースコレクションを返すクラスも生成できます。カスタムする場合は以下の様にします。
```php
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と同じ内容を返すことができます。
```php
// 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に壁打ちしながら作成したものとなります。）


## 参考
https://readouble.com/laravel/10.x/ja/eloquent-resources.html

https://qiita.com/kenji123/items/06f8f2a476235bdf0046

https://qiita.com/mikakane/items/e46617b6960a7e77ca2b