1. 18:55 12/08/2026
Khi một web/app bắt đầu có nhiều màn hình, nhiều client hoặc tích hợp với đối tác bên ngoài, API không còn là phần giao tiếp nội bộ đơn giản. Một thay đổi tưởng như nhỏ, chẳng hạn đổi tên trường dữ liệu hoặc chuyển kiểu số sang chuỗi, có thể khiến ứng dụng di động cũ ngừng hoạt động. Vì vậy, thiết kế API cần tính đến khả năng tiến hóa ngay từ đầu.
1. Xem API như một hợp đồng
API là hợp đồng giữa bên cung cấp dữ liệu và bên sử dụng dữ liệu. Hợp đồng này không chỉ gồm URL, mà còn bao gồm:
- Tên và kiểu dữ liệu của các trường.
- Ý nghĩa của từng giá trị trạng thái.
- Cấu trúc phản hồi thành công và lỗi.
- Quy tắc phân trang, sắp xếp và lọc.
- Cách xác thực và các mã trạng thái HTTP.
Trước khi thay đổi một endpoint, hãy tìm hiểu client nào đang sử dụng nó. Một trường được xem là không còn cần thiết ở giao diện web có thể vẫn rất quan trọng với ứng dụng mobile chưa được cập nhật.
2. Ưu tiên mở rộng thay vì phá vỡ tương thích
Một nguyên tắc thực tế là thêm mới thường an toàn hơn thay đổi hoặc xóa. Ví dụ, nếu phản hồi cũ có trường status với giá trị pending, paid và canceled, bạn có thể bổ sung refunded thay vì đổi toàn bộ tên trường hoặc cấu trúc trạng thái.
Khi cần thêm dữ liệu, client cũ thường có thể bỏ qua trường mới. Ngược lại, việc đổi tên userName thành username hoặc chuyển một giá trị từ số sang object có thể gây lỗi ở nhiều nơi mà server không nhận biết ngay.
Nếu bắt buộc phải thay đổi không tương thích, hãy cân nhắc một phiên bản API mới, chẳng hạn /api/v2/orders. Tuy nhiên, tạo phiên bản mới không nên là cách né tránh mọi thiết kế kém. Mỗi phiên bản cần có kế hoạch hỗ trợ, tài liệu và thời điểm ngừng sử dụng rõ ràng.
3. Dùng giá trị mặc định và xử lý dữ liệu thiếu
Client nên chịu được trường dữ liệu vắng mặt, còn server nên trả về cấu trúc nhất quán. Với một tính năng mới như hasDiscount, tài liệu cần nói rõ giá trị mặc định khi trường không xuất hiện. Trong nhiều trường hợp, trả về false rõ ràng sẽ dễ xử lý hơn việc bắt client suy đoán null có nghĩa gì.
Dù vậy, không nên tùy tiện biến mọi giá trị thiếu thành chuỗi rỗng hoặc số 0. null, rỗng và không tồn tại có thể mang các ý nghĩa khác nhau. Hãy thống nhất quy ước và mô tả bằng ví dụ thực tế.
4. Tài liệu hóa bằng ví dụ có thể chạy thử
Tài liệu tốt nên có request, response, mã lỗi và các trường hợp biên. Một endpoint tạo đơn hàng có thể được mô tả với các tình huống như thiếu địa chỉ giao hàng, sản phẩm hết hàng hoặc yêu cầu bị gửi lại.
Nếu có thể, hãy duy trì schema API trong một định dạng máy đọc được và dùng nó để hỗ trợ sinh tài liệu, kiểm tra contract hoặc tạo mock server. Điều này giúp phát hiện việc tài liệu nói một đằng nhưng mã nguồn trả về một nẻo.
5. Kiểm thử contract trong quy trình phát triển
Kiểm thử unit chưa chắc phát hiện được lỗi tương thích giữa backend và frontend. Contract test tập trung vào những gì client thực sự kỳ vọng: trường nào phải có, kiểu dữ liệu là gì, mã lỗi nào được chấp nhận và cấu trúc phản hồi ra sao.
Một quy trình đơn giản có thể gồm:
- Lưu các ví dụ request và response quan trọng.
- Chạy kiểm tra khi backend thay đổi schema.
- Kiểm tra với ít nhất một client cũ nếu sản phẩm có nhiều phiên bản.
- Ghi nhận endpoint và trường dữ liệu sắp ngừng sử dụng.
Cuối cùng, hãy coi việc thiết kế API là công việc sản phẩm chứ không chỉ là việc đặt tên route. Hợp đồng rõ ràng, thay đổi có chủ đích và kiểm thử tương thích sẽ giúp đội ngũ phát triển nhanh hơn mà không phải liên tục sửa chữa những lỗi phát sinh từ các client đang tồn tại.