Mục lục

Lesson 2.2: Response Envelope

Cách đóng gói dữ liệu trả về nhất quán để Client dễ dàng xử lý và tích hợp.

API Design
JSON
Standards

Thời lượng: 20 phút
Level: Beginner
Yêu cầu: Đã hiểu về khái niệm API Contract.

Mục tiêu bài học

Sau bài học này, bạn sẽ:

  • Hiểu khái niệm Response Envelope (Lớp bọc dữ liệu).
  • Thiết kế được cấu trúc JSON trả về nhất quán cho mọi API.
  • Biết cách xử lý metadata (phân trang, thông tin bổ sung) trong Envelope.

Nội dung chính

1. Response Envelope là gì?

Thay vì trả về dữ liệu thô (raw data), chúng ta bọc nó trong một đối tượng JSON cố định.

Tại sao cần?

  • Đồng nhất: Mobile/Web app chỉ cần viết một hàm xử lý response duy nhất cho toàn bộ hệ thống.
  • Thông tin bổ sung: Dễ dàng kẹp thêm các thông tin như tổng số trang, trace_id, hoặc tin nhắn thông báo mà không làm hỏng cấu trúc dữ liệu chính.

2. Cấu trúc chuẩn đề xuất

Một Response Envelope tốt thường chia làm 4 phần:

json:
{
  "success": true,
  "data": { ... },
  "error": null,
  "meta": { ... }
}
TrườngKiểu dữ liệuÝ nghĩa
successBooleanThành công (true) hoặc Thất bại (false).
dataObject / ArrayChứa dữ liệu thực tế mà người dùng yêu cầu.
errorObject / nullChứa thông tin lỗi nếu success là false.
metaObjectChứa thông tin bổ sung (phân trang, thời gian xử lý...).

3. Ví dụ chi tiết

Trường hợp Thành công (Lấy danh sách sản phẩm)

json:
{
  "success": true,
  "data": [
    { "id": 1, "name": "iPhone 15" },
    { "id": 2, "name": "MacBook M3" }
  ],
  "meta": {
    "current_page": 1,
    "total_items": 100,
    "items_per_page": 20
  }
}

Trường hợp Thất bại (Sai mật khẩu)

json:
{
  "success": false,
  "data": null,
  "error": {
    "code": "AUTH_001",
    "message": "Mật khẩu không chính xác",
    "target": "password"
  },
  "meta": {
    "request_id": "req-99abc"
  }
}

Nguyên tắc then chốt

"Đừng bao giờ trả về mảng (array) ở lớp ngoài cùng của JSON."

Nếu bạn trả về [ {id:1}, {id:2} ], sau này bạn muốn thêm thông tin phân trang (pagination), bạn sẽ phải thay đổi cấu trúc hoàn toàn, gây "vỡ" client. Luôn bọc mảng trong một object: { "data": [...] }.


Thực hành

Bài tập 1: Nâng cấp API thô thành API Standard

Bối cảnh: Bạn có một API cũ trả về danh sách user như sau: [ {"username": "huy"}, {"username": "nguyen"} ]

Yêu cầu:

  • Chuyển đổi response này sang dạng Envelope.
  • Thêm request_id vào phần meta.

Gợi ý:

Xem đáp án mẫu
json:
{
  "success": true,
  "data": [
    { "username": "huy" },
    { "username": "nguyen" }
  ],
  "meta": {
    "request_id": "888-999-000"
  }
}

Tình huống thực tế

Scenario 1: Hệ thống Microservice đa ngôn ngữ

Bối cảnh: Project của bạn có Service viết bằng Go, Service viết bằng Node.js. Mỗi ông viết một kiểu response khác nhau. Coder Frontend đang kêu trời vì mỗi trang phải viết code xử lý API một kiểu.

Giải pháp:

  • Định nghĩa một thư viện dùng chung (Shared Library) hoặc Template chứa cấu trúc Envelope này.
  • Mọi service bắt buộc phải dùng chung cấu trúc này thông qua Governance (kiểm tra ở bước Code Review).

Câu hỏi phỏng vấn

Junior/Mid Level

  1. Q: Tại sao không nên trả về mảng JSON trực tiếp ở root? A: Vì nó không có khả năng mở rộng. Khi cần thêm metadata (phân trang, thống kê), chúng ta buộc phải thay đổi cấu trúc response, dẫn đến việc phải cập nhật toàn bộ client (App/Web).

Tóm tắt

Những điều cần nhớ

  • Envelope giúp Client code "nhàn" hơn và hệ thống chuyên nghiệp hơn.
  • data chỉ dành cho nội dung chính.
  • meta dành cho các thông tin vận hành và bổ trợ.
  • error phải chuẩn hóa mã lỗi để Client có thể xử lý logic (VD: hiển thị popup hoặc chuyển hướng).

Bước tiếp theo

Bài tiếp theo: Lesson 2.3: HTTP Semantics - Cách sử dụng đúng các mã trạng thái (200, 404, 500) và các phương thức (GET, POST, PUT) để API của bạn "chuẩn REST".

Tiếp tục →

Quảng cáo
mdhorizontal