【Laravel】APIリソースを使う(Json/Resource)
LaravelのAPIリソースを使ってとても便利だと思ったのでまとめ。
https://readouble.com/laravel/5.5/ja/eloquent-resources.html
APIリソースとは(日本訳ドキュメント引用)
API構築時、Eloquentモデルと、アプリケーションユーザーに対して実際に返信するJSONリスポンスとの間に、
トランスレーション層を設置することが必要となります。
Laravelのリソースクラスは、モデルやモデルコレクションを記述しやすく簡単に、JSONへと変換してくれます。
ちなみにLaravel5.5で登場したそうです。最高です。
完成形
- 一覧
- ID指定
こんな感じです。
前準備
- 環境構築(Laravelプロジェクト)
- Controllerの作成
- Modelの作成
- Route通す
- DBにPostとCommentを準備
用意したデータ
- postsテーブル
- commentsテーブル
ディレクトリ構成
App
┗Http
┝Controllers
┝BaseController.php
┝PostController.php
┗CommentController.php
┝Resources
┝BaseResource.php
┝Post.php
┗Comment.php
┝Models
┝BaseModel.php
┝Post.php
┗Comment.php
┝Repositories
┝BasePost.php
┝Post.php
┗Comment.php
┗Services
┝BaseService.php
┝Post.php
┗Comment.php
深くなりましたが
APIリソースに深く関わるのは
・取得するデータのロジックを記載するRepository
・インスタンス化するService
・レスポンスを定義するResourceクラス
この3つです。
イメージを明確にするために、補足でController/ Route/ Modelは画像のみ貼っておきます。
Route
Controller
Model
※PostにひもづくCommentも取得したいのでリレーション定義
リソースに渡すモデルを取得
今回はRepositoryクラスに実装します。
リソースの作成
まずはリソースクラスを作成します。
- Postリソース
今回はPost一覧を求められた場合、
Postのもつid,title,body,とそのPostにひもづくCommentを取得したい。
渡したい情報をそれぞれキー(クラスにより自由です)、
そして渡したモデルの誰がそのデータを持っているか渡してあげます。
CommentはPostと1対多の関係、つまりは1Postが複数のCommentを持ちうるので
Commentリソースについてcollectionメソッドを用います。
このように、APIリソースはそれらのリレーションで紐付く情報も
プロパティから呼び出して別のリソースを整形して同時に返却することができます。
<?php namespace App\Http\Resources; use App\Http\Resources\Comment as CommentResource; use Illuminate\Http\Resources\Json\Resource; class Post extends Resource { public function toArray($request) { return [ 'id' => $this->id, 'title' => $this->title, 'body' => $this->body, 'comments' => CommentResource::collection($this->comments) ]; } }
- Commentリソース
コメントではid,post_id,bodyを返却したいのでそれぞれ定義して返します。
<?php namespace App\Http\Resources; use Illuminate\Http\Resources\Json\Resource; class Comment extends Resource { public function toArray($request) { return [ 'id' => $this->id, 'post_id' => $this->post_id, 'body' => $this->body ]; } }
リソースをインスタンス化する
リソースを実際に使用するときは、DBから取得したデータを
引数として渡しつつ、インスタンス化します。
リソースが1つの時は newでインスタンス化すれば良いですが、
複数のコレクションの場合はcollectionメソッドを用います。
<?php namespace App\Services; use App\Http\Resources\Post as PostResource; use App\Repositories\Post as PostRepository; class Post extends BaseService { private $post_repository; public function __construct(PostRepository $post_repository) { $this->post_repository = $post_repository; } /** * 全てのPostを取得し成型してJsonで返す * * @return mixed */ public function getAllPosts() { return PostResource::collection($this->post_repository->getAllPosts()); } /** * IDからPostを取得し成型してJsonで返す * * @param int $id * @return mixed */ public function getPostById(int $id) { return new PostResource($this->post_repository->getPostById($id)); } }
これで、URLを叩くと
データが返ってきましたね!
リソースはいくつも階層重ねることもできるので、
ドメイン的な整形の仕方にももってこいですね。
積極的に使っていきたいです
以上