Part 05 · API · 5.1.03

Resource model và API contract

Một contract tốt mô tả resource và invariant mà client cần, không phơi bày schema database hay implementation detail. OpenAPI hỗ trợ thực thi contract, nhưng không thay thế quyết định semantics.

Design test: với mỗi endpoint, hãy viết được resource/action, owner/authorization boundary, trạng thái lỗi, consistency expectation và cách client tiến hóa.

1. Resource boundaries

URI nên định danh collection, item hoặc subresource theo domain lifecycle, không chỉ sao chép bảng. /orders/{id}/items hợp khi item phụ thuộc order; command endpoint như /orders/{id}/cancel hợp khi operation không ánh xạ CRUD tự nhiên. Dù chọn cách nào, method, status và transition phải rõ.

2. Schema, validation và errors

Schema cần nói rõ required/optional/null, enum, precision, timezone, identifier format và unknown-field policy. Validation cú pháp nằm ở boundary; business invariant và authorization cần current state trong use case. Normalize/canonicalize trước comparison chỉ khi quy tắc được tài liệu hóa.

{
  "code": "VALIDATION_FAILED",
  "message": "Request contains invalid fields",
  "traceId": "req-7f3a",
  "violations": [{"field":"currency","reason":"unsupported"}]
}

Field errors phải machine-readable nhưng không leak SQL, stack trace, token hay thông tin giúp attacker enumerate resource.

3. Filtering và sorting an toàn

Cho phép allow-list field/operator thay vì ghép query tùy ý. Values luôn parameterize; identifiers được map qua allow-list. Giới hạn query complexity, page size, regex/costly filter và số quan hệ expand để tránh unrestricted resource consumption. Sorting cần deterministic tie-breaker, thường là id, để pagination không đảo thứ tự khi nhiều row bằng nhau.

4. Pagination và consistency

StrategyƯu điểmTrade-off cần nói
Offset/pageDễ hiểu, jump tới trangDeep offset chậm; insert/delete giữa các page gây drift/duplicate
Cursor/keysetỔn định và nhanh theo index ở tập lớnCursor opaque; cần encode order/filter/version và giới hạn sửa
Snapshot tokenRõ consistency giữa nhiều pageTốn storage/retention; phải định nghĩa expiry và stale behavior

Cursor nên chứa giá trị order cuối, filter fingerprint và version; ký hoặc mã hóa khi client không được sửa. Response cần nextCursor, max limit và tuyên bố dữ liệu có thể thay đổi giữa các page hay không.

5. Compatibility và versioning

Additive optional field thường tương thích nếu client bỏ qua unknown fields, nhưng đổi type/meaning, biến optional thành required hoặc thêm enum mà client không chịu unknown có thể breaking. Tolerant reader không phải giấy phép cho server mơ hồ.

6. Bulk và asynchronous operation

Bulk endpoint phải công bố atomicity (all-or-nothing hay per-item), thứ tự, giới hạn kích thước và outcome từng item. Long-running operation nên trả 202 Accepted cùng operation resource để poll trạng thái/cancel. Webhook callback cần signature, replay protection, bounded retry và idempotency.

Review checklist: resource name có phản ánh lifecycle không; schema có phân biệt null/absent không; query có allow-list và max cost không; cursor có deterministic order không; breaking change có telemetry và migration path không?
Tài liệu: OpenAPI Specification · RFC 9110 HTTP Semantics · RFC 9457 Problem Details