+3

Dọn rác file Routes: Chuẩn hóa RESTful API với Resource Controller trong Laravel và những "Tuyệt kỹ" ẩn giấu

Chào anh em cộng đồng Viblo!

Lại là câu chuyện muôn thuở về Clean Code. Đã bao giờ anh em mở file routes/api.php hoặc routes/web.php của một dự án cũ ra và bị "tẩu hỏa nhập ma" bởi hàng trăm dòng định nghĩa route dài ngoằng chưa?

Nó thường trông như thế này:

Route::get('/get-all-products', [ProductController::class, 'getAll']);
Route::post('/product/add-new', [ProductController::class, 'submitNewProduct']);
Route::get('/product/detail/{id}', [ProductController::class, 'getDetail']);
Route::post('/product/update-data/{id}', [ProductController::class, 'updateData']);
Route::get('/product/delete/{id}', [ProductController::class, 'remove']); // Dùng GET để xóa???

Nhìn vào đoạn code trên, mỗi Dev trong team đặt tên route một kiểu, gọi HTTP Method (GET, POST) lộn xộn. Nếu cứ tiếp tục scale hệ thống lên hàng chục thực thể (Category, Order, User, Voucher...), file Route của bạn sẽ biến thành một bãi rác khổng lồ không thể bảo trì.

Để giải quyết bài toán này, các hệ thống lớn luôn tuân thủ chuẩn RESTful, và Laravel cung cấp một vũ khí tối thượng để ép team bạn vào khuôn khổ: Resource Controller. Lên xe thôi!

1. Resource Controller là gì?

Thay vì phải tự tay định nghĩa 5-7 cái routes cho các thao tác CRUD (Create, Read, Update, Delete) cơ bản của một thực thể (như Product), Resource Controller gom tất cả chúng lại vào một dòng code duy nhất.

Nó tự động ánh xạ các HTTP Method chuẩn (GET, POST, PUT/PATCH, DELETE) vào 7 hàm mặc định trong Controller: index, create, store, show, edit, update, destroy.

2. Lột xác code: Chuyển từ "Cơm bình dân" sang "Fine Dining"

Giả sử chúng ta đang xây dựng module quản lý sản phẩm mỹ phẩm cho hệ thống bán lẻ.

Bước 1: Tạo Controller chuẩn Resource Bạn chỉ cần thêm cờ --resource (hoặc -r) khi dùng Artisan:

php artisan make:controller ProductController --resource

Laravel sẽ tự động sinh ra một class với đầy đủ 7 hàm trống rỗng. Bạn chỉ việc điền logic vào.

Bước 2: Định nghĩa Route cực kỳ thanh lịch Xóa sạch đống rác ở đầu bài viết đi, thay vào đó chỉ cần đúng 1 dòng này trong file routes/web.php:

use App\Http\Controllers\ProductController;

Route::resource('products', ProductController::class);

Chỉ 1 dòng này, Laravel đã tự động ngầm định tạo ra cho bạn 7 routes cực kỳ chuẩn RESTful:

  1. GET /products -> Hàm index (Lấy danh sách)
  2. GET /products/create -> Hàm create (Hiển thị form tạo mới)
  3. POST /products -> Hàm store (Lưu data mới)
  4. GET /products/{product} -> Hàm show (Xem chi tiết 1 SP)
  5. GET /products/{product}/edit -> Hàm edit (Hiển thị form sửa)
  6. PUT/PATCH /products/{product} -> Hàm update (Lưu data update)
  7. DELETE /products/{product} -> Hàm destroy (Xóa SP)

Code của bạn giờ đây đã đạt cảnh giới: Dễ đọc, dễ đoán, và chuẩn quốc tế!

3. Những "Tuyệt kỹ" Hạng Nặng cho Senior Backend

Dùng Route::resource thì ai cũng biết, nhưng để làm chủ nó trong các hệ thống phức tạp, bạn cần nắm vững các kỹ năng sau:

Tuyệt kỹ 1: apiResource - Vũ khí cho Backend API Nếu bạn đang viết API (chỉ trả về JSON) cho Frontend (React/Vue/Mobile App) thay vì trả về giao diện Blade HTML, bạn KHÔNG CẦN 2 hàm create (form tạo) và edit (form sửa).

Đừng dùng Route::resource, hãy dùng:

Route::apiResource('products', ProductController::class);

Nó sẽ tự động cắt bỏ 2 route HTML thừa thãi kia, chỉ giữ lại 5 thao tác tương tác dữ liệu thuần túy (index, store, show, update, destroy). Lệnh sinh Controller tương ứng là: php artisan make:controller ProductController --api.

Tuyệt kỹ 2: Lọc route với only và except Đôi khi bạn có một Resource Controller, nhưng nghiệp vụ không cho phép người dùng được quyền Xóa (destroy) hóa đơn, hoặc không cho phép Cập nhật (update) giao dịch đã hoàn tất. Đừng để route thừa mở ra ngoài, hãy đóng nó lại:

// Chỉ sinh ra route để Xem danh sách và Xem chi tiết
Route::apiResource('transactions', TransactionController::class)->only([
    'index', 'show'
]);

// Sinh ra tất cả, NGOẠI TRỪ hàm xóa
Route::apiResource('orders', OrderController::class)->except([
    'destroy'
]);

Tuyệt kỹ 3: Nested Resources (Tài nguyên lồng nhau) Giả sử hệ thống mỹ phẩm của bạn yêu cầu: Mỗi Product sẽ có nhiều bài Review. Bạn muốn URL trông chuyên nghiệp như vầy: /products/15/reviews/3 (Xem review số 3 của sản phẩm số 15).

Chỉ cần khai báo lồng nhau (Dot notation):

Route::resource('products.reviews', ProductReviewController::class);

Controller của bạn lúc này sẽ tự động nhận được cả 2 tham số:

public function show(Product $product, Review $review)
{
    // Cực kỳ tiện lợi để truy vấn!
}

Tuyệt kỹ 4: Shallow Nesting (Chống URL "Dài như sớ")

Lồng nhau thì hay, nhưng nếu lồng quá sâu sẽ phản tác dụng. Ví dụ: PUT /products/15/reviews/3. Thực chất, để CẬP NHẬT review số 3, ta chỉ cần ID của review đó là đủ truy vấn DB rồi, việc mang theo products/15/ là thừa thãi và làm URL quá dài.

Laravel có tuyệt chiêu


All Rights Reserved

Viblo
Let's register a Viblo Account to get more interesting posts.