2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Laravel+vueでなんか作る(Laravel基礎④ ~JSON Resource編~)

Posted at

当記事はUdemyの講座、Vue 3 and Laravel: A Practical Guide with Dockerを進めるにあたり、理解を深めるために記された備忘録です。

この講座はフロントエンドをVue3のSPA、バックエンドをLaravelのAPIという構成でアプリを開発するのですが、この場合、JSONを用いた両者の通信を整頓するにはシリアライズが不可欠です。というわけで今回はResourceの使い方を見ていきます。

Resourceとは何か?

Railsでいう所のシリアライザ。
コントローラが返すJSONのフォーマットを決められる。

App\Http\Resources\UserResource
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するなら、

App\Http\Resources\UserResource
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);
    }
返り値をPostmanで見るとこんな感じ
{
    "data": {
        "id": 24,
        "first_name": "John",
        "last_name": "Smith",
        "email": "01@test.io",
        "role": {
            "id": 3,
            "name": "viewer"
        }
    }
}

ちなみに、デフォルトではResourceを噛ませた返り値は「data」内に格納される。それが嫌な人はAppServiceProvider内で以下のように設定すれば裸で返せる。

App\Providers\AppServiceProvider
use Illuminate\Http\Resources\Json\JsonResource;

// ~ 中 略 ~
    public function boot()
    {
        JsonResource::withoutWrapping();
    }
}

入れ子のResource

実はResource内の返り値に別のResourceを使うこともできる。
上記のUserテーブルがRoleテーブルにbelongsToする例で行けば、

App\Http\Resources\UserResource
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に準ずることになる。

Postmanの返り値は例えばこんな感じ
{
    "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を書き換える必要がある。

App\Http\Resources\UserResource
return [
            "id"=>$this->id,
            "first_name"=>$this->first_name,
            "last_name"=>$this->last_name,
            "email"=>$this->email,
            "role"=>new RoleResource($this->whenLoaded("role"))
        ];

これでコントローラの記述に準じたクエリを行ってくれる。

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?