Appearance
理查森成熟度模型
本章导读:如何衡量一个 API "有多 REST"?Leonard Richardson 提出的成熟度模型(RMM)给出了一个广受欢迎的四级标尺。学完本章,你可以快速给自己的项目定级,并明确改进路线——每一级的提升都直接对应真实收益(可路由、可理解、可演进)。
1. 模型总览
理查森成熟度模型(Richardson Maturity Model)把 API 的 REST 化程度分为 0~3 级:
Level 3 超媒体控制(HATEOAS) ← 像浏览器一样"发现"操作
↑
Level 2 HTTP 资源与动词 ← 正确的 URI + 方法 + 状态码
↑
Level 1 资源(Resources) ← 把单体拆成多个端点
↑
Level 0 沼泽(The Swamp) ← 只有一个端点,全用 POST该模型由 Leonard Richardson 在 2008 年提出,Martin Fowler 网站收录的专题文章《Richardson Maturity Model》是最广为流传的解读版本。
下面用一个博客场景的例子逐级演示。
2. Level 0:POX 沼泽
只有一个端点,所有请求都用 POST 发送,"做什么"完全写在报文里——HTTP 只是消息投递管道(Plain Old XML/JSON over HTTP):
http
POST /blog-service HTTP/1.1
Content-Type: application/json
{ "action": "publishArticle", "articleId": 42 }http
POST /blog-service HTTP/1.1
Content-Type: application/json
{ "action": "listArticles", "authorId": 7, "page": 2 }问题:
- 网关、防火墙、缓存、监控对 URL 一无所知(全是同一个端点)。
- 成功失败全靠私有字段约定,无法用状态码做通用处理。
- API 行为没有公共标准可循,只能靠口口相传的文档。
Level 0 的改进方向:把动作拆到不同的资源端点上。
3. Level 1:资源
引入"资源"概念——为每类信息提供独立端点,并区分"单个资源"与"集合资源":
http
POST /articles/42/publish ← 针对"文章 42"这个资源
POST /authors/7/articles ← 针对"作者 7 的文章集合"但此级别下方法仍是"随手用"的(常常全部 POST),状态码也基本只用 200。
收益: URL 开始具备可路由性与可理解性;资源建模倒逼团队思考领域结构。
改进方向:为操作选择正确的 HTTP 方法与状态码。
4. Level 2:HTTP 动词与状态码
这是现代 API 工程实践中**"RESTful"的默认水位线**。规则来自 RFC 9110:
4.1 方法映射到意图
http
GET /articles/42 → 读取文章
POST /articles → 新建文章
PATCH /articles/42 → 修改标题(局部更新)
DELETE /articles/42 → 删除文章"发布"这类动词型操作有两种规范化处理:
http
# 方案 A:把状态当资源(推荐,PUT 幂等)
PUT /articles/42/status
Body: { "status": "published" }
# 方案 B:把"发布"建模为子资源(一次发布 = 创建一个发布记录)
POST /articles/42/publications4.2 状态码表达结果
| 场景 | 响应 |
|---|---|
| 找到文章 | 200 OK + body |
| 新建成功 | 201 Created + Location: /articles/43 |
| 删除成功无内容 | 204 No Content |
| 文章不存在 | 404 Not Found |
| 未登录 | 401 Unauthorized + WWW-Authenticate |
| 已登录但无权限 | 403 Forbidden |
| 标题超长校验失败 | 422 Unprocessable Content + 错误详情 |
| 并发编辑冲突 | 409 Conflict 或 412 Precondition Failed |
4.3 Level 2 的自检清单
- [ ] 读操作一律 GET(可缓存、可收藏、可预取)
- [ ] 创建用 POST,返回 201 + Location
- [ ] 全量替换用 PUT,局部修改用 PATCH
- [ ] 删除用 DELETE,语义见 204/202/410 的取舍
- [ ] 错误通过状态码区分,而不是
200 + code:-1
本教程第 02~05 篇的主体内容,就是教你把 Level 2 做扎实。
5. Level 3:超媒体驱动(HATEOAS)
Level 3 的要求:响应不仅包含数据,还包含"下一步可以做什么"的链接。客户端不需要硬编码 URL 模板,像浏览器点链接一样"发现" API:
json
GET /articles/42
{
"id": 42,
"title": "RESTful API 设计规范",
"status": "draft",
"_links": {
"self": { "href": "/articles/42" },
"author": { "href": "/authors/7" },
"publish": { "href": "/articles/42/status", "method": "PUT" },
"comments": { "href": "/articles/42/comments" },
"delete": { "href": "/articles/42", "method": "DELETE" }
}
}这是 Fielding 论文中"统一接口"约束的第四条:Hypermedia as the Engine of Application State(超媒体作为应用状态的引擎)。协议层的对应物是 RFC 8288 的 Link 头部,常见的 JSON 超媒体格式有 HAL、Siren、Collection+JSON。
真实收益(不只是优雅):
- 服务端改 URL 结构时,只要继续返回正确的
_links,老客户端不受影响——URL 成为实现细节而非契约。 - 可以按用户权限动态裁剪可用操作:无删除权限的客户端,响应里干脆不出现
delete链接。 - API 具备自描述性,文档与探索工具(如 API 浏览器)可以自动遍历。
6. 各级别的取舍:一定要做到 Level 3 吗?
社区的主流态度是务实的:Level 2 是目标,Level 3 是可选项。
| 考量 | 建议 |
|---|---|
| 内部系统、迭代快的团队 | Level 2 + OpenAPI 契约文档即可,HATEOAS 收益有限 |
| 对外平台型 API、版本包袱重 | 值得投入 Level 3(如 GitHub 大量使用 Link 头做分页与关联发现) |
| 面试/理论讨论 | 记住 Fielding 的立场:不支持超媒体就不能叫 REST;工程上普遍称 Level 2 为 "RESTful" |
7. 本章小结
- RMM 是衡量 API "REST 化程度"的四级标尺:0 沼泽 → 1 资源 → 2 方法与状态码 → 3 超媒体。
- 大多数团队的目标是把 Level 2 做彻底:方法语义正确、状态码丰富准确。
- Level 3 的 HATEOAS 提供真正的解耦能力,可用
Link头(RFC 8288)渐进式引入。
8. 下一步
- 深入 Level 2 背后的理论基础 → REST 六大约束