API Design
API 是协作边界,不是内部实现的直接映射。
API Design = Boundary Design
核心目标
好的 API = 易理解 + 可演进 + 可安全运行。
- 易理解:命名、资源和行为符合已有约定;常见任务不需要 workaround。
- 可演进:优先向后兼容的增量变更;把不稳定的实现细节藏在契约后面。
- 可安全运行:明确超时、重试、幂等、限流、权限和错误语义。
设计原则
- 先建模,再选协议:先明确资源、关系和动作,再决定 REST、RPC 或事件。
- 优先简单路径:让最常见的调用最短、最直观;复杂需求再提供扩展点。
- 行为要可预测:同一概念使用同一命名、状态和错误格式。
- 契约小而稳定:只暴露调用方真正需要的字段;避免泄露内部表结构。
- 显式表达意图:区分创建、更新、删除和动作,不用隐晦参数改变语义。
常用约定
GET /users/{id} # read
POST /users # create
PATCH /users/{id} # partial update
DELETE /users/{id} # delete
POST /users/{id}:disable # action that is not CRUD- 列表默认分页;优先使用稳定的
pageToken,不要依赖深分页的offset。 - 部分更新使用字段掩码或明确的
PATCH语义,避免并发下的读改写覆盖。 - 创建和有副作用的请求支持
Idempotency-Key,使客户端可以安全重试。 - 错误至少包含稳定的
code、可读的message和可定位的request_id。 - 不把
200 OK当作所有结果;正确使用201、202、204、4xx、5xx。
演进与安全
- 新增字段、端点和可选能力通常是兼容的;删除、改名、改变含义通常不是。
- 破坏性变更应显式版本化,并给出迁移和废弃周期。
- 服务端必须校验输入、鉴权每个操作,并限制请求大小、频率和资源消耗。
- 重试只适用于可判断安全的错误;超时不代表服务端没有执行成功。
提交前检查
- 调用方能否仅凭契约完成任务?
- 常见调用是否简单,异常和边界是否明确?
- 网络失败、重复请求和并发更新是否安全?
- 新旧客户端同时运行时,契约是否仍兼容?
- 是否暴露了不必要的实现细节、权限或数据?
links
- https://www.seangoedecke.com/good-api-design
- Dave Cheney: API Design as a Performance Primitive
评论