REST API(REST)
Kiểu API phổ biến nhất hiện nay: mỗi thứ trong hệ thống là một tài nguyên có địa chỉ riêng, thao tác bằng GET/POST/PUT/DELETE, dữ liệu đi về dưới dạng JSON.
Định nghĩa
Nếu API là khái niệm chung thì REST là kiểu API bạn gặp gần như mặc định mỗi lần mở tài liệu tích hợp của một đối tác trong nước. Ý tưởng gọn: mọi thứ trong hệ thống được coi là một tài nguyên, mỗi tài nguyên có một địa chỉ, và bạn tác động lên nó bằng vài động từ cố định.
Nhìn một URL và một động từ là đoán được nó làm gì — đó là toàn bộ sức hấp dẫn của REST.
Bảy thứ đọc được là đủ đi họp
- Tài nguyên số nhiều:
/customers,/orders,/invoices. Thấy/getCustomerListlà biết API đó không theo REST chuẩn, dù vẫn chạy được. - Động từ:
GET /orders/871lấy đơn 871;POST /orderstạo đơn mới;PUT /orders/871thay thế toàn bộ đơn — trường nào không gửi lên coi như bị xoá trắng;PATCH /orders/871chỉ sửa đúng vài trường gửi lên;DELETE /orders/871xoá. - Hai động từ ở giữa nhìn giống nhau nhưng hậu quả khác hẳn, nên trong tài liệu tích hợp phải ghi rõ dùng cái nào. Viết "dùng PUT để cập nhật số điện thoại khách" mà đối tác cài đúng chuẩn PUT là mất luôn địa chỉ và email của khách đó.
- Không nhớ trạng thái: mỗi lần gọi phải mang đủ thông tin, kể cả token. Máy chủ không nhớ bạn là ai từ lần trước.
- Status code: nhóm 2xx là xong, 4xx là lỗi do bên gọi, 5xx là lỗi bên nhận. Phân biệt được ba nhóm này là biết nên đi tìm ai khi có sự cố.
- Phân trang: danh sách dài luôn trả theo trang, kiểu
?page=2&limit=50. Không hỏi kỹ chỗ này là báo cáo thiếu dữ liệu mà không ai biết. - Phiên bản:
/v1/,/v2/. Đối tác nâng lên v2 thì bên mình có bắt buộc đổi theo không, và trong bao lâu.
Ví dụ request và response
Truy vấn danh sách hoá đơn chưa thanh toán của một khách:
GET /v2/invoices?customer_code=KH00123&status=unpaid&limit=2
Authorization: Bearer eyJhbGciOi...HTTP/1.1 200 OK
{
"data": [
{
"invoice_no": "HD-2026-004512",
"amount": 12500000,
"due_date": "2026-03-20",
"status": "unpaid"
},
{
"invoice_no": "HD-2026-004780",
"amount": 3200000,
"due_date": "2026-04-05",
"status": "unpaid"
}
],
"page": 1,
"total": 7
}Chú ý "total": 7 trong khi data chỉ có 2 dòng. Đây chính là chỗ phân trang, và cũng là chỗ một bạn dev từng quên khiến màn hình công nợ chỉ hiện 2 trong 7 hoá đơn.
So sánh REST API và Webhook
| Tiêu chí | REST API | Webhook |
|---|---|---|
| Ai gọi ai | Bên cần dữ liệu chủ động gọi sang | Bên có dữ liệu chủ động bắn sang khi có sự kiện |
| Thời điểm | Khi nào bên gọi muốn | Ngay khi sự kiện xảy ra |
| Kiểu tương tác | Đồng bộ, gọi xong chờ kết quả ngay | Bất đồng bộ, bên nhận chỉ trả lời đã nhận |
| Hợp cảnh nào | Tra cứu, tạo đơn, lấy danh sách theo yêu cầu người dùng | Báo thanh toán thành công, đơn đổi trạng thái, hàng về kho |
| Rủi ro chính | Gọi quá nhiều, chạm rate limit | Bắn trùng hoặc mất gói khi bên nhận sập |
Trong một tích hợp thật, hai thứ này thường đi cùng nhau: webhook báo có chuyện xảy ra, rồi bên nhận gọi REST API lấy chi tiết đầy đủ.
Ví dụ thực tế
Màn hình đối soát trắng xoá lúc 20h05, đúng ngày khuyến mãi. Chuyện là thế này: một ví điện tử cho phép cửa hàng tra cứu trạng thái giao dịch qua REST API, và đội vận hành bên bán lẻ dựng một màn hình cứ 30 giây lại gọi API cho từng giao dịch trong ngày. Ngày thường 8 nghìn giao dịch thì không sao. Ngày khuyến mãi lên 40 nghìn, số lần gọi vượt hạn mức, phía ví chặn IP trong 15 phút.
Cách sửa: chuyển sang nhận webhook cho các giao dịch đổi trạng thái, còn REST API chỉ dùng khi nhân viên bấm tra cứu một giao dịch cụ thể. Số lần gọi giảm hơn hai mươi lần.
Trước khi giao cho dev
Mở Postman, tự gọi thử ba trường hợp: một lần đúng, một lần thiếu trường bắt buộc, một lần với token hết hạn. Chụp lại ba kết quả, dán vào tài liệu. Rồi trước khi bấm gửi tài liệu đi, tự hỏi một câu: cái API mình vừa mô tả, mình đã tận mắt thấy nó trả dữ liệu về chưa, hay mới chỉ thấy nó trong bảng đặc tả của đối tác?
