REST API Design — Best Practices Cho Backend Developer
Thiết kế REST API chuẩn: đặt tên endpoint, versioning, error handling, pagination và nhiều hơn nữa.
API là cầu nối giữa frontend và backend. Một REST API được thiết kế tốt giúp frontend dễ dàng tích hợp, debug, và mở rộng.
1. Đặt Tên Endpoint#
Dùng Danh Từ Số Nhiều#
✅ GET /users # Danh sách user
✅ GET /users/:id # Chi tiết user
✅ POST /users # Tạo user
✅ PUT /users/:id # Cập nhật toàn bộ
✅ PATCH /users/:id # Cập nhật một phần
✅ DELETE /users/:id # Xóa user
❌ GET /getUsers # Dùng động từ
❌ GET /user # Số ít
❌ POST /createUser # Lặp động từ
❌ DELETE /deleteUser?id=1 # Query param để xóatxtResource Lồng Nhau#
GET /users/:id/posts # Bài viết của user
GET /users/:id/posts/:postId # Chi tiết bài viết
POST /users/:id/posts # Tạo bài viết cho usertxtActions — Khi CRUD Không Đủ#
POST /users/:id/activate # Kích hoạt user
POST /orders/:id/cancel # Hủy đơn hàng
POST /posts/:id/like # Thích bài viếttxtDùng POST thay vì GET/DELETE cho action — không phải action nào cũng là CRUD.
2. Versioning#
URL Path (Phổ biến nhất)#
- /api/v1/users
- /api/v2/users
Header (Less intrusive)#
Accept: application/vnd.myapp.v1+jsontxtURL path dễ đọc, dễ test, dễ route. Header “sạch” hơn về mặt REST thuần túy.
3. Response Format — Consistency Là Chìa Khóa#
// ✅ Consistent success
{
"data": { "id": 1, "name": "Alice" },
"meta": { "requestId": "req-123" }
}
// ✅ Consistent error
{
"error": {
"code": "VALIDATION_ERROR",
"message": "Email is required",
"details": [
{ "field": "email", "message": "must not be empty" }
]
}
}jsonPagination#
GET /users?page=1&limit=20
{
"data": [...],
"pagination": {
"page": 1,
"limit": 20,
"total": 150,
"totalPages": 8,
"hasNext": true,
"hasPrev": false
}
}jsonDùng cursor-based pagination cho real-time data (chat, feed):
GET /messages?cursor=eyJpZCI6MTB9&limit=20
{
"data": [...],
"nextCursor": "eyJpZCI6MzB9"
}json4. HTTP Status Code — Dùng Đúng Mã#
| Code | Ý nghĩa | Dùng khi |
|---|---|---|
| 200 | OK | Thành công |
| 201 | Created | POST tạo resource |
| 204 | No Content | DELETE thành công |
| 400 | Bad Request | Validation lỗi |
| 401 | Unauthorized | Chưa đăng nhập |
| 403 | Forbidden | Không có quyền |
| 404 | Not Found | Resource không tồn tại |
| 409 | Conflict | Trùng lặp, xung đột |
| 422 | Unprocessable Entity | Dữ liệu không hợp lệ |
| 429 | Too Many Requests | Rate limit |
| 500 | Internal Server Error | Lỗi server |
5. Filtering, Sorting, Searching#
# Filtering
GET /users?role=admin&status=active
# Sorting
GET /users?sort=name,-createdAt # name ASC, createdAt DESC
# Searching
GET /users?search=alice
# Field selection
GET /users?fields=id,name,emailbash6. Authentication#
JWT trong Header#
Authorization: Bearer <token>httpKhông dùng cookie cho mobile/SPA#
Trừ khi bạn cần bảo vệ khỏi XSS (httpOnly cookie). Cân nhắc:
- Bearer token — Đơn giản, mobile-friendly
- httpOnly cookie — Chống XSS, nhưng dễ bị CSRF
- Both — Access token (short-lived) + Refresh token (httpOnly)
7. Rate Limiting — Trả Về Header#
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 45
X-RateLimit-Reset: 1718845200http8. Idempotency — An Toàn Khi Retry#
POST /payments
Idempotency-Key: uuid-v4httpServer dùng key này để detect request trùng:
const existing = await cache.get(idempotencyKey);
if (existing) return existing;
const result = await processPayment(data);
await cache.set(idempotencyKey, result, { ttl: 86400 });
return result;typescriptCực kỳ quan trọng cho payment, order — nơi retry có thể gây hậu quả nghiêm trọng.
9. API Documentation#
Công cụ phổ biến cho API documentation:
- OpenAPI/Swagger — Tiêu chuẩn, sinh từ code
- Scalar — Giao diện đẹp, hiện đại
- Stoplight — Design-first API
# openapi.yaml
openapi: 3.1.0
info:
title: My API
version: 1.0.0
paths:
/users:
get:
summary: List users
parameters:
- in: query
name: page
schema: { type: integer }
responses:
'200':
description: User listyamlKết Luận#
REST API design không có “đúng tuyệt đối” — nhưng có những convention giúp API của bạn dễ dùng, dễ mở rộng. Quan trọng nhất: be consistent. Chọn một style và giữ nó xuyên suốt toàn bộ API.