Quay lại blog
laravel9 phút đọc

Xây dựng API có khả năng mở rộng với Laravel

Kiến trúc và các kỹ thuật xây dựng RESTful API scalable với Laravel — từ Repository Pattern, Queue Jobs đến API Rate Limiting và versioning.

V
Bởi Ventra Rocket
·Đăng ngày 10 tháng 3, 2026
#Laravel#API#PHP#Scalability#Queue

Laravel là framework PHP được lựa chọn hàng đầu cho việc xây dựng API backend. Với hệ sinh thái phong phú và cú pháp biểu cảm, Laravel cho phép team nhỏ xây dựng API production-ready nhanh chóng. Bài viết này chia sẻ kiến trúc và kỹ thuật mà Ventra Rocket sử dụng để xây dựng API phục vụ hàng triệu request mỗi ngày.

1. Repository Pattern cho Business Logic

Tách biệt database logic khỏi controller giúp code dễ test và bảo trì.

// app/Repositories/Contracts/OrderRepositoryInterface.php
interface OrderRepositoryInterface
{
    public function findById(int $id): ?Order;
    public function findByCustomer(int $customerId, array $filters = []): Collection;
    public function create(array $data): Order;
    public function updateStatus(int $id, string $status): bool;
}

// app/Repositories/EloquentOrderRepository.php
class EloquentOrderRepository implements OrderRepositoryInterface
{
    public function findByCustomer(int $customerId, array $filters = []): Collection
    {
        return Order::query()
            ->where('customer_id', $customerId)
            ->when(isset($filters['status']), fn($q) => $q->where('status', $filters['status']))
            ->when(isset($filters['from']), fn($q) => $q->where('created_at', '>=', $filters['from']))
            ->with(['items', 'shipping'])
            ->latest()
            ->get();
    }
}

// Bind trong AppServiceProvider
$this->app->bind(OrderRepositoryInterface::class, EloquentOrderRepository::class);

2. API Versioning

Versioning API là bắt buộc để duy trì backward compatibility.

// routes/api.php
Route::prefix('v1')->name('api.v1.')->group(function () {
    Route::apiResource('orders', V1\OrderController::class);
    Route::apiResource('products', V1\ProductController::class);
});

Route::prefix('v2')->name('api.v2.')->group(function () {
    Route::apiResource('orders', V2\OrderController::class);
});

API Resources cho response transformation

// app/Http/Resources/V2/OrderResource.php
class OrderResource extends JsonResource
{
    public function toArray(Request $request): array
    {
        return [
            'id'         => $this->id,
            'status'     => $this->status,
            'total'      => number_format($this->total_amount, 2),
            'currency'   => $this->currency ?? 'VND',
            'items'      => OrderItemResource::collection($this->whenLoaded('items')),
            'customer'   => new CustomerResource($this->whenLoaded('customer')),
            'created_at' => $this->created_at->toIso8601String(),
            'links'      => [
                'self'   => route('api.v2.orders.show', $this->id),
                'cancel' => $this->canCancel()
                    ? route('api.v2.orders.cancel', $this->id)
                    : null,
            ],
        ];
    }
}

3. Queue Jobs cho Heavy Processing

Đừng bao giờ xử lý tác vụ nặng trong request cycle. Đẩy vào queue.

// app/Jobs/ProcessOrderFulfillment.php
class ProcessOrderFulfillment implements ShouldQueue
{
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

    public int $tries = 3;
    public int $backoff = 60; // Retry sau 60 giây

    public function __construct(private readonly Order $order) {}

    public function handle(
        InventoryService $inventory,
        ShippingService $shipping,
        NotificationService $notifier
    ): void {
        DB::transaction(function () use ($inventory, $shipping, $notifier) {
            $inventory->reserve($this->order->items);
            $trackingCode = $shipping->createShipment($this->order);
            $this->order->update([
                'status'        => 'processing',
                'tracking_code' => $trackingCode,
            ]);
            $notifier->sendOrderConfirmation($this->order);
        });
    }

    public function failed(Throwable $exception): void
    {
        Log::error('Order fulfillment failed', [
            'order_id' => $this->order->id,
            'error'    => $exception->getMessage(),
        ]);
        $this->order->update(['status' => 'failed']);
    }
}

4. Rate Limiting

Bảo vệ API khỏi abuse với rate limiting linh hoạt.

// app/Providers/RouteServiceProvider.php
RateLimiter::for('api', function (Request $request) {
    return $request->user()
        ? Limit::perMinute(120)->by($request->user()->id)
        : Limit::perMinute(30)->by($request->ip());
});

RateLimiter::for('heavy-operations', function (Request $request) {
    return [
        Limit::perHour(10)->by($request->user()?->id ?? $request->ip()),
        Limit::perDay(50)->by($request->user()?->id ?? $request->ip()),
    ];
});

5. Caching Strategy

// app/Services/ProductCatalogService.php
class ProductCatalogService
{
    public function getByCategory(int $categoryId): Collection
    {
        return Cache::tags(['products', "category:{$categoryId}"])
            ->remember(
                "products.category.{$categoryId}",
                now()->addHours(2),
                fn () => Product::active()
                    ->inCategory($categoryId)
                    ->with(['images', 'variants'])
                    ->get()
            );
    }

    public function invalidateCategory(int $categoryId): void
    {
        Cache::tags(["category:{$categoryId}"])->flush();
    }
}

6. Error Handling chuẩn RFC 7807

// app/Exceptions/Handler.php
public function register(): void
{
    $this->renderable(function (ValidationException $e, Request $request) {
        if ($request->expectsJson()) {
            return response()->json([
                'type'    => 'https://example.com/errors/validation',
                'title'   => 'Validation Failed',
                'status'  => 422,
                'detail'  => 'One or more fields failed validation.',
                'errors'  => $e->errors(),
            ], 422);
        }
    });

    $this->renderable(function (ModelNotFoundException $e, Request $request) {
        if ($request->expectsJson()) {
            return response()->json([
                'type'   => 'https://example.com/errors/not-found',
                'title'  => 'Resource Not Found',
                'status' => 404,
            ], 404);
        }
    });
}

Kết luận

API scalable không chỉ là code chạy được — đó là kiến trúc cho phép team grow mà không phát sinh technical debt. Repository Pattern, versioning, queue và caching là bốn trụ cột mà mọi Laravel API production cần có. Ventra Rocket triển khai các pattern này trong mọi dự án backend.

Xây dựng API có khả năng mở rộng với Laravel | Ventra Rocket