REST API 设计与实现:从资源建模到可观测 API
0. 元信息
- 主题路径:
docs/topics/rest-api-design/README.md - 主分类:Web 与后端
- 辅助分类:工程技术
- 适合对象:会写后端 handler、SQL 和 HTTP 请求的开发者
- 建议周期:4~6 周(每周 8~10 小时)
- 前置知识:
network、http-1-2-3、db-and-sql - 最终目标:能设计并实现带 OpenAPI、鉴权、限流、版本化、缓存和 tracing 的生产 API
1. 学习路线
资源与 URL → 方法语义 → 状态码与 problem+json → 分页/过滤 → 认证授权 → 限流配额 → 缓存/ETag → 版本化 → OpenAPI → CORS/Webhook → 可观测与发布
2. 阶段周数分配
| 阶段 | 4 周 | 6 周 | 备注 |
|---|---|---|---|
| 1. 资源契约 | 1 | 1.5 | URL、method、error、分页 |
| 2. 安全治理 | 1 | 1.5 | OAuth2/JWT、授权、CORS |
| 3. 性能与交付 | 1 | 1.5 | rate-limit、ETag、idempotency、Webhook |
| 4. 契约与运行 | 1 | 1.5 | OpenAPI、版本化、trace、发布 |
3. 九阶段表
| 阶段 | 核心知识 | 实践产出 | 可观察学会标准 |
|---|---|---|---|
| 1 | 资源、集合、子资源、URI | 商品/订单资源图 | URL 无动词,边界明确 |
| 2 | GET/POST/PUT/PATCH/DELETE、safe/idempotent | CRUD 请求集 | 能解释重试后果 |
| 3 | 2xx/4xx/5xx、problem+json | 错误目录 | 401/403/404/409/422 不混用 |
| 4 | cursor 分页、filter、sort、fields | 列表 endpoint | 数据变化时不重不漏 |
| 5 | OAuth2、JWT、RBAC/ABAC、CORS | 权限矩阵 | 对象级授权有测试 |
| 6 | rate-limit、quota、429 | 网关策略 | 返回 Retry-After 并能压测 |
| 7 | Cache-Control、ETag、条件请求 | 缓存实验 | 304 与并发更新可解释 |
| 8 | versioning、OpenAPI 3.1、兼容 | 可 lint 的契约 | 能识别 breaking change |
| 9 | tracing、Webhook、发布 | 完整 API | trace 可串联同步和异步链路 |
4. 第一周任务
Day 1 约定:OpenAPI 3.1;JSON;UTF-8;时间用 RFC 3339 UTC;金额用整数最小货币单位;命令用
curl。
| 日 | 任务 | 当天交付 |
|---|---|---|
| Day 1 | 画商品、订单、订单项资源和生命周期 | 资源图与命名表 |
| Day 2 | 为 CRUD 选择 method 与返回码 | 请求/响应矩阵 |
| Day 3 | 定义 problem+json 错误目录 | 8 个错误示例 |
| Day 4 | 设计 cursor、filter、sort | 列表契约 |
| Day 5 | 写最小 OpenAPI 3.1 | 可校验 YAML |
| Day 6 | 加 Bearer auth、scope、对象授权 | 权限矩阵 |
| Day 7 | A:跑通商品/订单正常流;B:补未认证、越权、重复提交、并发更新 | curl 脚本和结果 |
可运行契约片段:
openapi: 3.1.0
info: {title: Shop API, version: 1.0.0}
paths:
/products/{productId}:
get:
parameters:
- {name: productId, in: path, required: true, schema: {type: string}}
responses:
'200':
description: Product
headers:
ETag: {schema: {type: string}}
content:
application/json:
schema: {$ref: '#/components/schemas/Product'}
'404':
description: Not found
content:
application/problem+json:
schema: {type: object}
components:
schemas:
Product:
type: object
required: [id, name]
properties:
id: {type: string}
name: {type: string}
5. 阶段通用验收
- 契约经 lint 且示例可被
curl重放;2. 正常、非法、未认证、越权、冲突、超限路径都有测试;3. 写清 method、状态码和 header 的理由;4. 日志不泄露 token/PII;5. 变更前后做兼容检查;6. 指标能区分 client/server error;7. 第三方能只看 OpenAPI 完成调用。
6. 最终验收
- 至少 12 个 endpoint、20 个契约测试、10 个错误案例;
- OpenAPI 3.1 可 lint、可渲染、可生成客户端;
- 演示 OAuth2/JWT、对象授权、rate-limit、版本迁移、ETag、idempotency 和 trace;
- 能用 15 分钟讲清资源边界、兼容策略与运行证据。
7. 综合项目
首选:设计并实现一个完整的电商商品 / 订单 API,含 OpenAPI 文档、鉴权、限流、版本化、可观测。
必须含商品、订单、订单项、库存;cursor 分页;problem+json;ETag/If-Match;Idempotency-Key;OAuth2/JWT;429;Webhook 签名和重试;trace id;兼容迁移说明。
备选:将一套遗留 RPC 接口重构为 REST API 并保留向后兼容。交付 adapter、映射表、双写/影子流量策略和弃用时间线。
8. 推荐开源资料
| 角色 | 资料 | 用法 |
|---|---|---|
| 契约 | OpenAPI Specification、Swagger UI、Redoc | 写、渲染契约 |
| 校验/生成 | Spectral、OpenAPI Generator | lint 与 SDK |
| 客户端 | Postman、Insomnia、Bruno | collection 与环境变量 |
| CLI | httpie、curl | 可复制的验证脚本 |
| 规范风格 | Stripe、Microsoft、Google API guides | 比较真实选择 |
| 网关 | Apigee、AWS API Gateway | auth、quota、部署 |
9. 学习资料汇聚(v0.3 自包含)
9.1 背景与动机
REST 是 Fielding 在 2000 年论文中总结的网络软件架构风格。它强调 client-server、stateless、cache、uniform interface、layered system,可选 code-on-demand。工程里的“REST API”常只取资源和 HTTP 语义。我们要区分架构约束、团队风格和工具默认值。
9.2 概念地图
flowchart LR
Resource[资源/URL] --> Method[HTTP method]
Method --> Status[状态码/problem+json]
Resource --> Query[分页/过滤]
Auth[OAuth2/JWT] --> Authorization[RBAC/ABAC/对象授权]
Gateway[API Gateway] --> Rate[rate-limit/quota]
Method --> Cache[Cache-Control/ETag]
Contract[OpenAPI/JSON Schema] --> Client[SDK/Postman/curl]
Version[版本化] --> Contract
Contract --> Runtime[实现]
Runtime --> Trace[日志/指标/tracing]
Runtime --> Webhook[Webhook/异步]
资源契约决定请求形状。安全、流控、缓存和兼容约束它的运行行为。OpenAPI 连接设计、实现、测试和客户端。trace 证明请求在同步与异步链路中发生了什么。
9.3 基础知识讲解
9.3.1 论文 / 规范
- Roy Fielding, Architectural Styles and the Design of Network-Based Software Architectures:REST 起源。
- RFC 9110, HTTP Semantics:方法、状态码、缓存语义。
- RFC 7807, Problem Details for HTTP APIs:统一错误对象。
9.3.2 书
- Leonard Richardson, Mike Amundsen, Sam Ruby, RESTful Web APIs。
- Arnaud Lauret, The Design of Web APIs。
- JJ Geewax, API Design Patterns。
9.3.3 博客 / 文档
- Stripe API 文档:idempotency、分页、错误风格。
- Microsoft REST API Gui:兼容与一致性。
- Google API Design Guide:资源导向设计。
- Apigee 文档 与 AWS API Gateway 文档:网关、配额、部署。
9.3.4 人物
- Roy Fielding:REST 与 HTTP 架构。
- Tim Berners-Lee:Web、URI、HTTP。
- Darrel Miller:OpenAPI Initiative 技术治理与工具生态。
9.3.5 方法
- Contract-first:先写 OpenAPI 和示例,再写 handler。
- Consumer-driven review:从调用方任务检查命名、错误和兼容。
- Single-variable test:一次只改变 method、header、身份或并发量。
- Compatibility budget:发布前列出 breaking change 与迁移期。
9.4 经典问题与经典案例
| 问题 | 为什么重要 | 最简答案 |
|---|---|---|
| URL 要不要放动词 | 统一接口可读性 | 用 /orders/{id},动作只在无法建模时用 command 子资源 |
| PUT 和 PATCH 怎么选 | 重试和覆盖语义不同 | PUT 替换完整表示;PATCH 按媒体类型应用变更 |
| 401 还是 403 | 客户端处理不同 | 缺少/无效认证用 401;身份有效但无权用 403 |
| 409 还是 422 | 冲突与字段错误不同 | 状态冲突用 409;语法正确但语义校验失败可用 422 |
| cursor 还是 offset | 大表写入时稳定性 | 稳定排序键 + cursor;后台小表可 offset |
| 如何防重复下单 | 网络重试不可避免 | Idempotency-Key + 请求指纹 + 原子存储结果 |
| 如何并发更新 | 防 lost update | ETag + If-Match,不匹配回 412 |
| 版本放哪里 | 影响缓存与路由 | 团队一致即可;优先兼容演进,重大断裂再新 major |
| Webhook 如何可靠 | 接收端会失败 | 签名、事件 id、快速 2xx、重试、去重、死信 |
| 如何定位慢请求 | 多层代理会切断上下文 | W3C trace context + request id + RED 指标 |
9.5 学习难点
- 概念难点:REST 约束、HTTP 语义和 CRUD 映射常被混成一件事。先逐条核对 Fielding 与 RFC 9110,再做资源案例。
- 思维难点:API 设计是给未知客户端长期使用。每个字段都问删除、重试、并发、兼容时发生什么。
- 工程难点:网关、应用、数据库、消息系统各持一部分状态。用 trace、idempotency store、outbox 和契约测试把边界变成可检查结果。
9.6 技术标准与接口
9.6.1 Entity
| 名称 | 版本 | 组织 | 状态 / 可访问性 |
|---|---|---|---|
| OpenAPI Specification | 3.1 | OpenAPI Initiative | 正式;Apache-2.0 仓库,规范公开 |
| JSON:API | 1.1 | JSON:API 社区 | 正式;公开 |
| JSON Schema | 2020-12 | JSON Schema / IETF 社区 | 正式;公开 |
| Problem Details for HTTP APIs | RFC 7807 | IETF | 已被 RFC 9457 更新;RFC 公开 |
| HAL | draft-kelly-json-hal | IETF Internet-Draft / HAL 社区 | 草案;公开 |
9.6.2 Scope
OpenAPI 描述 HTTP API;JSON Schema 描述数据约束;JSON:API 与 HAL 约定表示和链接;Problem Details 约定机器可读错误。它们不替代业务授权、事务设计或运行时保护。
9.6.3 Structure
OpenAPI 必会 paths、operations、parameters、requestBody、responses、components、securitySchemes;JSON Schema 必会 type、required、properties、组合与引用;Problem Details 必会 type/title/status/detail/instance。
9.6.4 Ecosystem
实现与工具包括 Swagger UI、Redoc、Spectral、OpenAPI Generator、Postman、Insomnia、Bruno、httpie、curl。API gateway 常用 Apigee、AWS API Gateway、Kong、Envoy。工具默认值不是规范。
9.6.5 Depth Tiers
| 层级 | 可观察能力 |
|---|---|
| L0 | 知道这些标准解决什么问题 |
| L1 | 看懂 schema、operation 和 problem body |
| L2 | 能正确编写、校验、生成客户端并调用 |
| L3 | 能解释语义、排错兼容/鉴权/缓存/限流问题 |
| L4 | 能设计扩展、治理规则与跨团队演进机制 |
本计划目标:L3。
9.6.6 Source
- OpenAPI Initiative 仓库:OpenAPI 3.1 原文与版本历史。
- IETF RFC Editor:RFC 9110、7807/9457、6585 等原文。
- JSON Schema 2020-12 与 JSON:API 1.1。
- 引用快照:2026-07-30。实施前检查更新、勘误与废止关系。
10. 常见误区
- 把 REST 等同 JSON over HTTP
- URL 里堆
/createOrder - POST 重试不做 idempotency
- 所有错误返回 200
- 只做 endpoint 级认证,不做对象授权
- JWT 放敏感信息或永不过期
- offset 分页用于高写入大表
- ETag 生成不稳定
- 429 不返回重试信息
- 为每次小改动升版本
- OpenAPI 与实现各写一份后漂移
- CORS 当认证
- Webhook 无签名、去重和重试
- 日志记录 token/完整个人数据
- 只看平均延迟。
11. 所有知识点分类(统一规则)
- 编程语言 2. 数据结构与算法 3. 计算机基础 4. 工程技术 5. Web 与后端 6. 前端与客户端 7. 数据与人工智能 8. 项目与职业能力 9. 安全与可靠性
本计划归属:Web 与后端 主 + 工程技术 辅。