Thời lượng: 20 phút
Level: Beginner
Yêu cầu: Đã nắm vững Resource Naming và Nesting.
Mục tiêu bài học
Sau bài học này, bạn sẽ:
- Xử lý được các hành động nghiệp vụ phức tạp không phải là CRUD thuần túy.
- Biết cách dùng Sub-resource để biểu diễn hành động (Action).
- Phân biệt được khi nào dùng
PATCHtrạng thái và khi nào dùngPOSThành động.
Nội dung chính
1. Khi CRUD không đủ
Trong thực tế, có những hành động không đơn thuần là "Tạo - Đọc - Sửa - Xóa". Ví dụ:
- Login/Logout.
- Hủy đơn hàng (Cancel).
- Phê duyệt (Approve).
- Gửi lại email xác nhận (Resend).
Mặc dù chúng ta CỐ GẮNG đưa mọi thứ về Resource, nhưng đôi khi làm vậy sẽ khiến API trở nên gượng ép và khó hiểu.
2. Các phương pháp xử lý
Phương pháp A: Sub-resource Action (Khuyên dùng)
Chúng ta coi hành động đó là một tài nguyên ảo lồng dưới tài nguyên chính.
POST /orders/1/cancelPOST /documents/5/approvePOST /users/8/resend-verification
Tại sao dùng POST? Vì hành động này làm thay đổi trạng thái server và thường không mang tính tuần hoàn (idempotent) theo cách đơn giản.
Phương pháp B: State Machine (Dùng cho thay đổi trạng thái)
Nếu hành động chỉ đơn giản là đổi một trường status, chúng ta dùng PATCH.
PATCH /orders/1body{ "status": "cancelled" }
Lưu ý: Chỉ dùng cách này nếu việc đổi status không kéo theo quá nhiều side-effects phức tạp (như hoàn tiền, gửi email cho 5 bên, cập nhật kho...).
Phương pháp C: Controller Resources (Dành cho Logic đặc biệt)
Dành cho những thứ không thuộc về một tài nguyên cụ thể nào.
POST /auth/loginPOST /search(Khi query quá dài, không thể dùng GET)
3. Login & Logout - Trường hợp đặc biệt
Nhiều người cố gắng dùng POST /sessions (Tạo phiên làm việc) và DELETE /sessions để chuẩn REST.
Tuy nhiên, dùng POST /auth/login và POST /auth/logout được chấp nhận rộng rãi vì nó rõ ràng về mặt nghiệp vụ (Semantic).
Nguyên tắc then chốt
"Ưu tiên danh từ, nhưng đừng ngại sử dụng động từ khi hành động đó mang ý nghĩa nghiệp vụ rõ rệt."
Nếu việc ép một động từ (Approve) thành danh từ (Approval) khiến URL trở nên kỳ quặc (POST /documents/1/approvals), hãy mạnh dạn dùng POST /documents/1/approve. Tính dễ hiểu (Readability) quan trọng hơn sự cứng nhắc của lý thuyết.
Thực hành
Bài tập 1: Thiết kế API cho tính năng "Gửi tiền" (Transfer)
Bối cảnh: Bạn cần thiết kế API để User A gửi tiền cho User B.
Yêu cầu:
- Chọn URL và Method phù hợp nhất.
- Giải thích tại sao chọn phương án đó.
Gợi ý:
Xem đáp án mẫu
Phương án: POST /accounts/transfer hoặc POST /transfers
Lý do: Đây là một hành động nghiệp vụ phức tạp, ảnh hưởng đến 2 tài nguyên khác nhau cùng lúc. Coi cuộc chuyển tiền là một tài nguyên (transfers) hoặc một hành động đặc biệt là hợp lý nhất. Tránh dùng PATCH /accounts/A vì nó không bao quát được toàn bộ giao dịch.
Tình huống thực tế
Scenario 1: Hủy đơn hàng (Cancel Order)
Vấn đề: Khi hủy đơn hàng, hệ thống phải:
- Đổi status thành
cancelled. - Hoàn tiền vào ví điện tử.
- Cập nhật lại số lượng kho sản phẩm.
- Gửi thông báo cho nhà bán hàng.
Giải quyết:
Trong trường hợp này, dùng POST /orders/{id}/cancel là tối ưu. Nó báo hiệu cho Backend rằng đây là một Quy trình nghiệp vụ (Business Process) chứ không chỉ là cập nhật dữ liệu thuần túy.
Câu hỏi phỏng vấn
Senior Level
- Q: Khi nào bạn quyết định dùng
POST /resource/:id/actionthay vìPATCH /resource/:id? A: Tôi sẽ dùngPOSThành động khi:- Hành động đó gây ra nhiều hiệu ứng phụ (side-effects) phức tạp.
- Hành động đó cần các input data không thuộc về resource model (VD: lý do hủy đơn).
- Hành động đó cần tính rõ ràng về nghiệp vụ (Explicit intent).
- Cần tính bảo mật riêng biệt cho hành động đó (VD: AI check, Verify).
Tóm tắt
Những điều cần nhớ
- Cố gắng dùng Nouns trước.
- Dùng
POSTcho các hành động phi-CRUD. - Đặt hành động làm sub-resource của tài nguyên chịu tác động.
- Ưu tiên sự rõ ràng (Clarity) và dễ hiểu cho người dùng API.
Module tiếp theo
🎉 Chúc mừng! Bạn đã hoàn thành toàn bộ Module 3: REST Design Patterns.
Giờ bạn đã là một chuyên gia về:
- Đặt tên tài nguyên chuẩn REST.
- Xử lý quan hệ cha-con lồng nhau.
- Thiết kế các hành động nghiệp vụ phức tạp.
Module tiếp theo: Module 4: Validation & Errors - Chúng ta sẽ học cách xây dựng hệ thống validate dữ liệu đầu vào và trả về thông báo lỗi cực kỳ thân thiện với người dùng.