模块 04第 1 学期 · 基础4 海报条目
API 与契约
登录后可在不同设备间同步进度。在此之前,进度只保存在当前浏览器中。
为什么重要
API 是一份承诺。一旦有移动应用、合作伙伴或 agent 依赖它,每次改动都可能弄坏某个你看不见的人。企业客户会根据你的 API 契约质量来评判你。
学习目标
- 用 OpenAPI 契约设计风格一致的 REST API。
- 让每个会修改数据的端点都具备幂等性。
- 在不破坏客户端的前提下为 API 和库做版本管理。
- 知道什么时候 gRPC 才是合适的工具。
课程内容
4.1 契约优先的设计
- 先写 OpenAPI spec;再据此生成类型、客户端、文档和 mock 服务器。
- 统一约定:资源用名词、路径用复数、标准状态码、游标分页、ISO 8601 时间戳。
- 全局统一一种错误格式(RFC 9457 Problem Details):
type、title、status、detail,外加请求 ID。 - 在边界处按 schema 校验每一个输入;拒绝未知字段。
- 绝不返回超出需要的字段(过度数据暴露是典型的 API 漏洞)。
4.2 幂等性 (14)
网络可能在服务器已经完成操作、客户端却还没收到响应时断开。客户端会重试。没有幂等性,客户就会被扣两次款。
模式(由 Stripe 推广开来):
- 客户端在 POST 时发送
Idempotency-Key: <uuid>。 - 服务器把 key + 请求哈希 + 响应存入一张带唯一约束的表。
- 再次收到相同的 key:返回已存储的响应,不要重新执行。
- 相同的 key、不同的请求体:返回 422 拒绝。
- key 在 24 小时或更长时间后过期。
GET、PUT 和 DELETE 本来就应该是幂等的。按这个标准去设计。
4.3 版本管理 (102, 103)
- API 版本管理:放在 URL(
/v1/)或请求头里。增量变更(新增可选字段)不属于破坏性变更;删除或重命名字段、改变类型或语义则属于破坏性变更。 - 弃用策略:先公告,添加
Deprecation和Sunset头,统计旧版本的使用量,然后再移除。 - 包使用语义化版本:
MAJOR.MINOR.PATCH。MAJOR 表示不兼容变更,MINOR 表示新增功能,PATCH 表示修复。用 lockfile 锁定依赖;不要相信别人会完美遵守 semver。
4.4 gRPC (100)
强类型、二进制、高速、支持流式,跑在 HTTP/2 上。非常适合大规模的内部服务间通信,不适合浏览器和公开 API。一人公司的创始人很少需要它;理解概念即可。
4.5 API 安全预告
每个对象都做授权(BOLA 是排名第一的 API 风险)、按 key 限流、分页上限、请求大小上限。详见 05 · 应用安全:OWASP Top 10:2025。
实验 4:交付一份契约
- 为你的核心资源写一份 OpenAPI spec;生成一个强类型客户端。
- 给支付或“创建订单”端点加上幂等 key;写一个测试,并发发送同一请求 5 次,断言只生成一条记录。
- 用正确的方式做一次破坏性变更:让 v2 与 v1 并行发布,并带上弃用头。
- CI 中的契约测试在实现偏离 spec 时会失败。
完成标准
AI 提示词包
- “根据这些路由生成一份 OpenAPI 3.1 spec,然后列出命名、状态码和错误结构上的不一致之处。”
- “给这个端点加上 Stripe 风格的幂等 key,用一张带唯一约束的 Postgres 表来支撑。处理好并发重复请求的情况。”