模块 04第 1 学期 · 基础4 海报条目

API 与契约

登录后可在不同设备间同步进度。在此之前,进度只保存在当前浏览器中。

为什么重要

API 是一份承诺。一旦有移动应用、合作伙伴或 agent 依赖它,每次改动都可能弄坏某个你看不见的人。企业客户会根据你的 API 契约质量来评判你。

学习目标

  1. 用 OpenAPI 契约设计风格一致的 REST API。
  2. 让每个会修改数据的端点都具备幂等性。
  3. 在不破坏客户端的前提下为 API 和库做版本管理。
  4. 知道什么时候 gRPC 才是合适的工具。

课程内容

4.1 契约优先的设计

  • 先写 OpenAPI spec;再据此生成类型、客户端、文档和 mock 服务器。
  • 统一约定:资源用名词、路径用复数、标准状态码、游标分页、ISO 8601 时间戳。
  • 全局统一一种错误格式(RFC 9457 Problem Details):type、title、status、detail,外加请求 ID。
  • 在边界处按 schema 校验每一个输入;拒绝未知字段。
  • 绝不返回超出需要的字段(过度数据暴露是典型的 API 漏洞)。

4.2 幂等性 (14)

网络可能在服务器已经完成操作、客户端却还没收到响应时断开。客户端会重试。没有幂等性,客户就会被扣两次款。

模式(由 Stripe 推广开来):

  1. 客户端在 POST 时发送 Idempotency-Key: <uuid>。
  2. 服务器把 key + 请求哈希 + 响应存入一张带唯一约束的表。
  3. 再次收到相同的 key:返回已存储的响应,不要重新执行。
  4. 相同的 key、不同的请求体:返回 422 拒绝。
  5. 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:交付一份契约

  1. 为你的核心资源写一份 OpenAPI spec;生成一个强类型客户端。
  2. 给支付或“创建订单”端点加上幂等 key;写一个测试,并发发送同一请求 5 次,断言只生成一条记录。
  3. 用正确的方式做一次破坏性变更:让 v2 与 v1 并行发布,并带上弃用头。
  4. CI 中的契约测试在实现偏离 spec 时会失败。

完成标准

AI 提示词包

  • “根据这些路由生成一份 OpenAPI 3.1 spec,然后列出命名、状态码和错误结构上的不一致之处。”
  • “给这个端点加上 Stripe 风格的幂等 key,用一张带唯一约束的 Postgres 表来支撑。处理好并发重复请求的情况。”