📦

API Resources

Tạo API Resource

php artisan make:resource PostResource
php artisan make:resource PostCollection --collection
<?php
// app/Http/Resources/PostResource.php

namespace App\Http\Resources;

use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\JsonResource;

class PostResource extends JsonResource
{
    public function toArray(Request $request): array
    {
        return [
            'id' => $this->id,
            'title' => $this->title,
            'slug' => $this->slug,
            'excerpt' => Str::limit($this->content, 150),
            'content' => $this->when($request->routeIs('posts.show'), $this->content),
            'status' => $this->status,
            'published_at' => $this->published_at?->toIso8601String(),
            'created_at' => $this->created_at->toIso8601String(),
            
            // Relationships
            'author' => new UserResource($this->whenLoaded('author')),
            'category' => new CategoryResource($this->whenLoaded('category')),
            'tags' => TagResource::collection($this->whenLoaded('tags')),
            
            // Conditional data
            'comments_count' => $this->whenCounted('comments'),
            'can_edit' => $this->when(
                $request->user()?->id === $this->user_id,
                true
            ),
            
            // Links
            'links' => [
                'self' => route('api.posts.show', $this),
                'comments' => route('api.posts.comments.index', $this),
            ],
        ];
    }
}

// Sử dụng trong Controller
class PostController extends Controller
{
    public function index()
    {
        $posts = Post::with(['author', 'category'])
            ->withCount('comments')
            ->published()
            ->paginate(15);

        return PostResource::collection($posts);
    }

    public function show(Post $post)
    {
        $post->load(['author', 'category', 'tags', 'comments.user']);
        
        return new PostResource($post);
    }
}

Rate Limiting

Định nghĩa Rate Limiters

<?php
// bootstrap/app.php (Laravel 11+)

use Illuminate\Cache\RateLimiting\Limit;
use Illuminate\Support\Facades\RateLimiter;

->withMiddleware(function (Middleware $middleware) {
    RateLimiter::for('api', function (Request $request) {
        return Limit::perMinute(60)->by($request->user()?->id ?: $request->ip());
    });
    
    // Premium users có rate cao hơn
    RateLimiter::for('api-premium', function (Request $request) {
        return $request->user()?->isPremium()
            ? Limit::perMinute(200)->by($request->user()->id)
            : Limit::perMinute(60)->by($request->ip());
    });
    
    // Rate limit cho uploads
    RateLimiter::for('uploads', function (Request $request) {
        return Limit::perHour(10)->by($request->user()->id);
    });
})

// routes/api.php
Route::middleware(['throttle:api'])->group(function () {
    Route::apiResource('posts', PostController::class);
});

Route::middleware(['throttle:uploads'])->group(function () {
    Route::post('/uploads', [UploadController::class, 'store']);
});
📋

API Versioning

Versioning với Prefix

<?php
// routes/api.php

// API v1
Route::prefix('v1')->group(function () {
    Route::apiResource('posts', App\Http\Controllers\Api\V1\PostController::class);
    Route::apiResource('users', App\Http\Controllers\Api\V1\UserController::class);
});

// API v2 - Breaking changes
Route::prefix('v2')->group(function () {
    Route::apiResource('posts', App\Http\Controllers\Api\V2\PostController::class);
    Route::apiResource('articles', App\Http\Controllers\Api\V2\ArticleController::class);
});

// Cấu trúc thư mục
// app/Http/Controllers/Api/V1/PostController.php
// app/Http/Controllers/Api/V2/PostController.php
// app/Http/Resources/V1/PostResource.php
// app/Http/Resources/V2/PostResource.php
💡 Best Practice: Dùng URL versioning (v1, v2) cho public APIs. Header versioning cho internal APIs.
← Bài 3: Authentication Bài 5: Queues & Jobs →