当記事はUdemyの講座、Vue 3 and Laravel: A Practical Guide with Dockerを進めるにあたり、理解を深めるために記された備忘録です。
この講座はフロントエンドをVue3のSPA、バックエンドをLaravelのAPIという構成でアプリを開発するのですが、この場合、JSONを用いた両者の通信を整頓するにはシリアライズが不可欠です。というわけで今回はResourceの使い方を見ていきます。
Resourceとは何か?
Railsでいう所のシリアライザ。
コントローラが返すJSONのフォーマットを決められる。
public function toArray($request)
{
return [
"id"=>$this->id,
"first_name"=>$this->first_name,
"last_name"=>$this->last_name,
"email"=>$this->email,
];
}
コントローラ側でインポートし、以下のように使う。
- 一つだけ返す場合
return response(new UserResource($user),Response::HTTP_CREATED);
- 配列を返す場合
return UserResource::collection(User::paginate());
ちなみに、関連テーブルも返せる。
たとえばUserテーブルがRoleテーブルにbelongsTo
するなら、
public function toArray($request)
{
return [
"id"=>$this->id,
"first_name"=>$this->first_name,
"last_name"=>$this->last_name,
"email"=>$this->email,
"role"=>$this->role,
];
}
と書けば、コントローラ側でUser::with("role")->find($id)
とか書かなくても、ちゃんとRoleテーブルをJoinしてくれるのだ。
public function show($id)
{
$user = User::find($id);
return new UserResource($user);
}
{
"data": {
"id": 24,
"first_name": "John",
"last_name": "Smith",
"email": "01@test.io",
"role": {
"id": 3,
"name": "viewer"
}
}
}
ちなみに、デフォルトではResourceを噛ませた返り値は「data」内に格納される。それが嫌な人はAppServiceProvider内で以下のように設定すれば裸で返せる。
use Illuminate\Http\Resources\Json\JsonResource;
// ~ 中 略 ~
public function boot()
{
JsonResource::withoutWrapping();
}
}
入れ子のResource
実はResource内の返り値に別のResourceを使うこともできる。
上記のUserテーブルがRoleテーブルにbelongsTo
する例で行けば、
return [
"id"=>$this->id,
"first_name"=>$this->first_name,
"last_name"=>$this->last_name,
"email"=>$this->email,
"role"=>new RoleResource($this->role)
];
と書けば、new UserResource($user)
のroleプロパティの構造は、RoleResource
に準ずることになる。
{
"id": 24,
"first_name": "John",
"last_name": "Smith",
"email": "01@test.io",
"role": {
"id": 3,
"name": "viewer"
}
}
whenLoaded()
ただし、これには一つ欠点がある。
入れ子のResourceを使った場合、コントローラで返す値がUser::with("role")->find($id);
だろうがUser::find($id);
だろうが、強制的にRoleテーブルをJOINしてクエリを行うのだ。
これを改善するには、以下のようにResourceを書き換える必要がある。
return [
"id"=>$this->id,
"first_name"=>$this->first_name,
"last_name"=>$this->last_name,
"email"=>$this->email,
"role"=>new RoleResource($this->whenLoaded("role"))
];
これでコントローラの記述に準じたクエリを行ってくれる。