Giới Thiệu
Khi chúng ta nói về việc xây dựng API, thường thì trọng tâm sẽ nằm ở các endpoint và tính năng. Tuy nhiên, một phần rất quan trọng là phản hồi API thường bị xem nhẹ. Nếu định dạng phản hồi không hợp lý, điều này có thể gây khó khăn cho frontend, làm cho việc gỡ lỗi trở nên phức tạp và tiêu tốn băng thông hơn cần thiết.
Trong bài viết này, chúng ta sẽ khám phá cách thức xây dựng định dạng phản hồi API lý tưởng: ngắn gọn, nhất quán, dễ dàng theo dõi và thân thiện với frontend.
Tại Sao Định Dạng Phản Hồi API Quan Trọng?
- Tính Nhất Quán → Frontend không cần phải tạo ra hàng ngàn điều kiện đặc biệt để phân tích JSON.
- Hiệu Quả → Không lãng phí băng thông với các trường dữ liệu dư thừa.
- Dễ Gỡ Lỗi → Có
request_idđể theo dõi trong log backend một cách nhanh chóng. - Hỗ Trợ Đa Ngôn Ngữ → Mã lỗi tiêu chuẩn có thể được dịch sang ngôn ngữ của người dùng từ phía frontend.
Tóm lại, việc này giúp cuộc sống của các lập trình viên frontend trở nên dễ dàng hơn và giúp lập trình viên backend dễ dàng hơn trong việc theo dõi lỗi. Đó là một sự thắng lợi cho cả hai bên!
Nguyên Tắc Cơ Bản Của Định Dạng Phản Hồi
Có một số nguyên tắc mà chúng ta nên tuân theo:
- Mã trạng thái HTTP được sử dụng để chỉ trạng thái chính (200, 400, 401, 404, 500, v.v.).
- Nội dung phản hồi tập trung vào nội dung →
datanếu thành công,errornếu thất bại. - Luôn có
request_idđể theo dõi. - Lỗi sử dụng mã tiêu chuẩn → Phía frontend sẽ xác định thông điệp thân thiện với người dùng.
Ví Dụ Về Định Dạng Phản Hồi Nhất Quán
✅ Phản Hồi Thành Công – Tài Nguyên Đơn
json
{
"request_id": "uuid",
"data": {
"id": 123,
"name": "Nandan",
"email": "nandan@example.com"
}
}
✅ Phản Hồi Thành Công – Danh Sách + Phân Trang
json
{
"request_id": "uuid",
"items": [
{ "id": 1, "title": "Mục Đầu Tiên" },
{ "id": 2, "title": "Mục Thứ Hai" }
],
"meta": {
"page": 1,
"per_page": 10,
"total": 25
}
}
❌ Lỗi Xác Thực (400/422)
json
{
"request_id": "uuid",
"error": {
"message": "Lỗi Xác Thực Payload",
"code": "VALIDATION_ERROR",
"fields": {
"email": ["BẮT BUỘC", "ĐỊNH DẠNG KHÔNG HỢP LỆ", "DUY NHẤT"],
"password": ["BẮT BUỘC", "ĐỘ DÀI TỐI THIỂU"]
}
}
}
❌ Lỗi Không Được Phép (401)
json
{
"request_id": "uuid",
"error": {
"message": "Không Được Phép",
"code": "UNAUTHORIZED"
}
}
❌ Lỗi Không Tìm Thấy (404)
json
{
"request_id": "uuid",
"error": {
"message": "Tài Nguyên Không Tìm Thấy",
"code": "NOT_FOUND"
}
}
❌ Lỗi Lỗi Máy Chủ (500)
json
{
"request_id": "uuid",
"error": {
"message": "Lỗi Máy Chủ Nội Bộ",
"code": "INTERNAL_ERROR"
}
}
Danh Sách Mã Lỗi Tiêu Chuẩn
Để đảm bảo tính nhất quán, backend cần sử dụng các mã lỗi rõ ràng. Frontend chỉ cần ánh xạ mã này với thông điệp phù hợp với ngôn ngữ.
🔹 Xác Thực
REQUIRED→ trường dữ liệu trống nhưng bắt buộcINVALID_TYPE→ kiểu dữ liệu saiINVALID_FORMAT→ định dạng sai (ví dụ: email không hợp lệ)MIN_LENGTH/MAX_LENGTH→ chiều dài chuỗi không phù hợpMIN_VALUE/MAX_VALUE→ số không phù hợp với giới hạnUNIQUE→ dữ liệu đã tồn tại (ví dụ: email đã được sử dụng)ENUM_VALUE→ giá trị không hợp lệMISMATCH→ xác nhận không khớp (ví dụ: password & confirm_password)
🔹 Bảo Mật & Xác Thực
UNAUTHORIZED→ chưa đăng nhập / token không cóINVALID_TOKEN→ token hết hạn hoặc saiFORBIDDEN_ACTION→ người dùng không có quyềnACCOUNT_LOCKED→ tài khoản bị khóaTOO_MANY_REQUESTS→ giới hạn tỷ lệ đạt
🔹 Máy Chủ
INTERNAL_ERROR→ lỗi không mong đợiSERVICE_UNAVAILABLE→ dịch vụ phụ thuộc không khả dụngTIMEOUT→ thời gian chờ yêu cầuCONFLICT→ xung đột tài nguyên
Tại Sao Không Cần Thêm Trường Như resource?
Đơn giản là: nếu chúng ta yêu cầu tới /users/123 và phản hồi là 404 NOT_FOUND, đã rõ tài nguyên mà chúng ta đang nói tới là user. Việc thêm "resource": "user" vào body có thể tạo ra sự không nhất quán vì không phải tất cả các lỗi đều cần trường này. Do đó, chúng ta nên tối thiểu hóa và duy trì tính nhất quán.
Kết Luận
Định dạng phản hồi API lý tưởng là:
- Thành Công →
datahoặcitems + meta. - Lỗi → luôn có
error.message+error.code(vàfieldsnếu có lỗi xác thực). - Luôn có
request_id. - Frontend sẽ dịch mã lỗi, không phải backend.
Với định dạng này:
- Backend nhẹ nhàng hơn và tiết kiệm băng thông.
- Frontend linh hoạt hơn và có thể hỗ trợ đa ngôn ngữ.
- Gỡ lỗi dễ dàng hơn nhờ có
request_id.
👉 Vì vậy, trước khi nghĩ đến việc triển khai microservices hay mở rộng phức tạp, hãy đảm bảo rằng API của bạn có phản hồi nhất quán, gọn gàng và thân thiện với lập trình viên. Tin tôi đi, điều này sẽ tiết kiệm rất nhiều thời gian và công sức cho đội ngũ trong tương lai.