Giao diện
Eloquent: API Resources
Giới thiệu (Introduction)
Khi xây dựng API, bạn có thể cần một lớp chuyển đổi (transformation layer) nằm giữa Eloquent model và JSON response trả về cho người dùng. Ví dụ, bạn muốn hiển thị một số thuộc tính cho nhóm user nhất định nhưng không cho nhóm khác, hoặc bạn muốn luôn bao gồm relationship nhất định trong JSON.
Eloquent resource class cho phép bạn chuyển đổi model và model collection thành JSON một cách linh hoạt và dễ dàng.
Tạo Resources (Generating Resources)
Sử dụng lệnh Artisan make:resource. Resource class mặc định nằm trong app/Http/Resources và kế thừa Illuminate\Http\Resources\Json\JsonResource:
bash
php artisan make:resource UserResourceResource Collections
Ngoài resource cho model đơn, bạn có thể tạo resource cho collection. Sử dụng flag --collection hoặc thêm từ Collection vào tên:
bash
php artisan make:resource User --collection
php artisan make:resource UserCollectionCollection resource kế thừa Illuminate\Http\Resources\Json\ResourceCollection.
Tổng quan khái niệm (Concept Overview)
Resource class đại diện cho một model cần chuyển thành JSON:
php
<?php
namespace App\Http\Resources;
use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\JsonResource;
class UserResource extends JsonResource
{
/**
* Chuyển resource thành mảng.
*
* @return array<string, mixed>
*/
public function toArray(Request $request): array
{
return [
'id' => $this->id,
'name' => $this->name,
'email' => $this->email,
'created_at' => $this->created_at,
'updated_at' => $this->updated_at,
];
}
}Method toArray trả về mảng thuộc tính để chuyển thành JSON. Truy cập thuộc tính model trực tiếp qua $this vì resource class tự proxy tới model bên dưới.
Sử dụng resource từ route hoặc controller:
php
use App\Http\Resources\UserResource;
use App\Models\User;
Route::get('/user/{id}', function (string $id) {
return new UserResource(User::findOrFail($id));
});Hoặc sử dụng method toResource:
php
return User::findOrFail($id)->toResource();Resource Collections
Nếu trả về collection hoặc paginated response, sử dụng collection:
php
use App\Http\Resources\UserResource;
use App\Models\User;
Route::get('/users', function () {
return UserResource::collection(User::all());
});Viết Resources (Writing Resources)
Resource chỉ cần chuyển đổi model thành mảng. Mọi public property và method trên model đều truy cập được qua $this:
php
public function toArray(Request $request): array
{
return [
'id' => $this->id,
'name' => $this->name,
'email' => $this->email,
'posts' => PostResource::collection($this->posts),
'created_at' => $this->created_at,
'updated_at' => $this->updated_at,
];
}Bọc dữ liệu (Data Wrapping)
Mặc định, resource được bọc trong key data trong JSON response:
json
{
"data": [
{
"id": 1,
"name": "Eladio Schroeder Sr.",
"email": "therese28@example.com"
},
{
"id": 2,
"name": "Liliana Mayert",
"email": "eveline@example.com"
}
]
}Tắt data wrapping:
php
use Illuminate\Http\Resources\Json\JsonResource;
JsonResource::withoutWrapping();Phân trang (Pagination)
Truyền paginated result vào resource:
php
use App\Http\Resources\UserResource;
use App\Models\User;
Route::get('/users', function () {
return UserResource::collection(User::paginate());
});Response sẽ chứa thêm meta và links:
json
{
"data": [...],
"links": {
"first": "http://example.com/users?page=1",
"last": "http://example.com/users?page=1",
"prev": null,
"next": null
},
"meta": {
"current_page": 1,
"from": 1,
"last_page": 1,
"path": "http://example.com/users",
"per_page": 15,
"to": 10,
"total": 10
}
}Thuộc tính có điều kiện (Conditional Attributes)
Bao gồm thuộc tính chỉ khi đáp ứng điều kiện:
php
public function toArray(Request $request): array
{
return [
'id' => $this->id,
'name' => $this->name,
'email' => $this->when($request->user()->isAdmin(), $this->email),
'secret' => $this->when($request->user()->isAdmin(), 'secret-value'),
];
}Relationship có điều kiện (Conditional Relationships)
Chỉ include relationship nếu đã được load:
php
public function toArray(Request $request): array
{
return [
'id' => $this->id,
'name' => $this->name,
'email' => $this->email,
'posts' => PostResource::collection($this->whenLoaded('posts')),
'updated_at' => $this->updated_at,
];
}Thêm Meta Data
Thêm meta data vào resource response:
php
public function with(Request $request): array
{
return [
'meta' => [
'key' => 'value',
],
];
}Meta data top-level khi tạo resource:
php
return (new UserCollection(User::all()->load('roles')))
->additional(['meta' => [
'key' => 'value',
]]);JSON:API Resources
Laravel 13.x hỗ trợ tạo resource theo chuẩn JSON:API bằng flag --jsonapi:
bash
php artisan make:resource UserResource --jsonapiResource Responses
Tùy chỉnh HTTP response:
php
use App\Http\Resources\UserResource;
use App\Models\User;
Route::get('/user/{id}', function (string $id) {
return (new UserResource(User::findOrFail($id)))
->response()
->header('X-Value', 'True');
});Hoặc định nghĩa method withResponse trên resource:
php
public function withResponse(Request $request, JsonResponse $response): void
{
$response->header('X-Value', 'True');
}