Hướng dẫn sử dụng laravel resource

  • December 3, 2022
  • 898

Khi chúng ta muốn custom dữ liệu trả về của api, chúng ta sẽ sử dụng laravel resource, hoặc sử dụng packgist bên thứ 3 như Dingo API. Hôm nay chúng ta sẽ tìm hiểu Laravel resource để transform dữ liệu trả về của api.

Laravel create resource

Tạo resource api với command, các files resource được tạo trong folder app/Http/Resources


php artisan make:resource UserResource

// Create resource collection
php artisan make:resource User --collection
 
php artisan make:resource UserCollection

Create base resource

Tạo 1 file BaseResource đinh nghĩa response trả về cho api


<?php

namespace App\Http\Resources;

use Illuminate\Http\Resources\Json\JsonResource;

class BaseResource extends JsonResource
{
    /**
     * @var string
     */
    public $msg;

    public function __construct($resource = null, $msg = 'success')
    {
        parent::__construct($resource);
        $this->msg = $msg;
    }

    /**
     * Transform the resource into an array.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return array|\Illuminate\Contracts\Support\Arrayable|\JsonSerializable
     */
    public function toArray($request)
    {
        return parent::toArray($request);
    }

    /**
     * Get additional data that should be returned with the resource array.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return array
     */
    public function with($request)
    {
        return [
            'status' => true,
            'message' => $this->msg,
        ];
    }
}

Create resource for model

Tạo UserResource để transform dữ liệu trả về cho api detail user.


<?php

namespace App\Http\Resources\Users;

use App\Http\Resources\BaseResource;

class UserResource extends BaseResource
{
    /**
     * Transform the resource into an array.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return array|\Illuminate\Contracts\Support\Arrayable|\JsonSerializable
     */
    public function toArray($request)
    {
        return [
            'name' => $this->name,
            'email' => $this->email,
        ];
    }
}

Tạo api get detail user


<?php

namespace App\Http\Controllers\Api\V1;

use App\Http\Controllers\Controller;
use App\Http\Requests\Users\UpdateUserRequest;
use App\Http\Resources\PaginationResource;
use App\Http\Resources\SuccessResource;
use App\Http\Resources\Users\UserResource;
use App\Http\Resources\Users\UsersResource;
use App\Models\User;

class UserController extends Controller
{
     /**
     * Detail user
     *
     * @OA\Get(
     *     path="/api/v1/users/{userId}",
     *     tags={"Users"},
     *     security={ {"sanctum" : {} }},
     *     @OA\Parameter(ref="#/components/parameters/userId"),
     *     @OA\Response(
     *          response=200,
     *          description="Successful operation",
     *          @OA\JsonContent(ref="#/components/schemas/UserResource")
     *     ),
     * )
     * @param int $id
     * @return UserResource
     */
    public function show(int $id): UserResource
    {
        $user = User::find($id);

        return new UserResource($user);
    }
}

Response api get detail đã được transfrom và trả về theo format sau


{
  "data": {
    "name": "huunv",
    "email": "huunv@gmail.com"
  },
  "status": true,
  "message": "success"
}

Create resource collection

Tạo collection resource để định nghĩa response chung trả về


<?php

namespace App\Http\Resources;

use Illuminate\Http\Resources\Json\ResourceCollection;

class CollectionResource extends ResourceCollection
{
    /**
     * @var string
     */
    public $msg;

    public function __construct($resource = null, $msg = 'success')
    {
        parent::__construct($resource);
        $this->msg = $msg;
    }

    /**
     * Transform the resource collection into an array.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return array
     */
    public function toArray($request)
    {
        return [
            'data' => $this->collection,
        ];
    }

    /**
     * Get additional data that should be returned with the resource array.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return array
     */
    public function with($request)
    {
        return [
            'status' => true,
            'message' => $this->msg,
        ];
    }
}

Tạo UsersResource trả về response với data trả về là 1 collection.


<?php

namespace App\Http\Resources\Users;

use App\Http\Resources\CollectionResource;
use App\Http\Resources\Users\UserResource;

class UsersResource extends CollectionResource
{
    /**
     * Transform the resource collection into an array.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return array
     */
    public function toArray($request)
    {
        return [
            // Transform data by UserResource
            //'data' => UserResource::collection($this->collection),
            // Get all data in collection
            //'data' => $this->collection,
            // Custom transfrom data
            'data' => $this->collection->transform(function($user) {
                return [
                    'id' => $user->id,
                    'title' => $user->name,
                    'slug' => $user->email,
                ];
            }),
        ];
    }
}

Controller trả về resource collection


<?php

namespace App\Http\Controllers\Api\V1;

use App\Http\Controllers\Controller;
use App\Http\Resources\Users\UsersResource;
use App\Models\User;

class UserController extends Controller
{
    /**
     * List users
     *
     * @OA\Get(
     *      path="/api/v1/users",
     *      tags={"Users"},
     *      security={ {"sanctum" : {} }},
     *      @OA\Response(
     *          response=200,
     *          description="Successful operation",
     *          @OA\JsonContent(ref="#/components/schemas/UsersResource")
     *       ),
     *      @OA\Response(
     *          response=401,
     *          description="Unauthenticated",
     *      ),
     *      @OA\Response(
     *          response=403,
     *          description="Forbidden"
     *      )
     *     )
     */
    public function index()
    {
        $user = User::orderByDesc('id')->get();

        return new UsersResource($user);
    }
}

Response trả về cho api get list users


{
  "data": [
    {
      "id": 2,
      "name": "huunv2",
      "email": "huunv2@gmail.com"
    },
    {
      "id": 1,
      "name": "huunv",
      "email": "huunv@gmail.com"
    }
  ],
  "success": true,
  "message": "success"
}

Create resource pagination

Tạo file PagintionResource transform data dạng phân trang


<?php

namespace App\Http\Resources;

use Illuminate\Http\Resources\Json\ResourceCollection;

class PaginationResource extends ResourceCollection
{
    /**
     * @var array
     */
    protected $pagination;

    protected $msg;

    public function __construct($resource, $msg = 'success')
    {
        $this->pagination = [
            'total' => $resource->total(),
            'per_page' => $resource->perPage(),
            'current_page' => $resource->currentPage(),
            'last_page' => $resource->lastPage(),
            'total_page' => ceil($resource->total() / $resource->perPage()),
        ];
        $this->msg = $msg;
        $resource = $resource->getCollection();

        parent::__construct($resource);
    }

    /**
     * Transform the resource into an array.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return array|\Illuminate\Contracts\Support\Arrayable|\JsonSerializable
     */
    public function toArray($request)
    {
        return [
            'data' => $this->collection,
            'pagination' => $this->pagination,
            'status' => true,
            'message' => $this->msg,
        ];
    }
}

Tạo UsersPaginationResource để transform data dang pagination.


<?php

namespace App\Http\Resources\Users;

use App\Http\Resources\PaginationResource;
use App\Http\Resources\Users\UserResource;

class UsersPaginationResource extends PaginationResource
{
    /**
     * Transform the resource into an array.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return array|\Illuminate\Contracts\Support\Arrayable|\JsonSerializable
     */
    public function toArray($request)
    {
        return [
            'data' => UserResource::collection($this->collection),
            'pagination' => $this->pagination,
            'status' => true,
            'message' => $this->msg,
        ];
    }
}

Tạo controller trả về UsersPaginationResource


<?php

namespace App\Http\Controllers\Api\V1;

use App\Http\Controllers\Controller;
use App\Http\Resources\Users\UsersPaginationResource;

class UserController extends Controller
{
    /**
     * List users
     *
     * @OA\Get(
     *      path="/api/v1/users",
     *      tags={"Users"},
     *      security={ {"sanctum" : {} }},
     *      @OA\Response(
     *          response=200,
     *          description="Successful operation",
     *          @OA\JsonContent(ref="#/components/schemas/UsersResource")
     *       ),
     *      @OA\Response(
     *          response=401,
     *          description="Unauthenticated",
     *      ),
     *      @OA\Response(
     *          response=403,
     *          description="Forbidden"
     *      )
     *     )
     */
    public function index()
    {
        $users = User::paginate(2);

        return new UsersPaginationResource($users);
    }
}

Response của api trả về với dạng pagination


{
  "data": [
    {
      "id": 1,
      "name": "huunv",
      "email": "huunv@gmail.com"
    },
    {
      "id": 2,
      "name": "huunv2",
      "email": "huunv2@gmail.com"
    }
  ],
  "pagination": {
    "total": 2,
    "per_page": 2,
    "current_page": 1,
    "last_page": 1,
    "total_page": 1
  },
  "status": true,
  "message": "success"
}

Create resource success

Tạo file SuccessResource trả về response trường hợp không cần trả về data, như api xoá user.


<?php

namespace App\Http\Resources;

use Illuminate\Http\Resources\Json\JsonResource;

/**
 * @OA\Schema(
 *      properties={
 *          @OA\Property(
 *              property="success",
 *              type="bool",
 *              example="true"
 *          ),
 *          @OA\Property(
 *              property="data",
 *              example=null,
 *          ),
 *          @OA\Property(
 *              property="message",
 *              type="string",
 *              example="success"
 *          )
 *      }
 * )
 */
class SuccessResource extends JsonResource
{
    /**
     * @var string
     */
    public $msg;

    public function __construct($msg = 'success')
    {
        $this->msg = $msg;
    }

    /**
     * Transform the resource into an array.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return array|\Illuminate\Contracts\Support\Arrayable|\JsonSerializable
     */
    public function toArray($request)
    {
        self::withoutWrapping();
        return [
            'data' => null,
            'status' => true,
            'message' => $this->msg,
        ];
    }
}

Tạo api delete user trả về SuccessResource


<?php

namespace App\Http\Controllers\Api\V1;

use App\Http\Controllers\Controller;
use App\Http\Resources\SuccessResource;

class UserController extends Controller
{
    /**
     * Delete user
     *
     * @OA\Delete(
     *     path="/api/v1/users/{userId}",
     *     tags={"Users"},
     *     security={ {"sanctum" : {} }},
     *     @OA\Parameter(ref="#/components/parameters/userId"),
     *     @OA\Response(
     *          response=200,
     *          description="Successful operation",
     *          @OA\JsonContent(ref="#/components/schemas/SuccessResource")
     *     ),
     * )
     * @param int $id
     * @return SuccessResource
     */
    public function destroy(int $id): SuccessResource
    {
        User::where(['id' => $id])->delete();

        return new SuccessResource('Delete success');
    }
}

Response api trả về


{
  "data": null,
  "status": true,
  "message": "Delete success"
}

Tổng kết

Như Vậy là chúng ta đã transform dữ liệu thành công khi sử dụng resource api, giúp cho ứng dụng của bạn trở lên cực kì mạnh mẽ rồi đó. Thanks for reading...