Richardson 成熟度模型 (RMM):迈向 RESTful API 的终极形态与 2026 前沿实践

由 Leonard Richardson 提出的 Richardson 成熟度模型 (RMM) 是一种用于根据 API 的实现级别来评估其 RESTful 成熟度的模型。它包含四个级别,每个级别都代表了 RESTful 原则在设计与实现中的成熟阶段。在这篇文章中,我们将深入探讨每一个级别,并结合 2026 年的开发实践,看看我们是如何在实际项目中评估和升级我们的 API 架构的。

在确定服务的成熟度时,Richardson 强调了三个主要因素。它们包括:

  • URI
  • HTTP 方法
  • HATEOAS (超媒体)

虽然这些概念已经存在了很长时间,但在 AI 辅助编程和云原生架构普及的今天,重新审视它们对于我们构建健壮的系统至关重要。

目录

  • URI
  • HTTP 方法
  • HATEOAS
  • 级别 0:POX 的沼泽
  • 级别 1:资源
  • 级别 2:HTTP 动词
  • 级别 3:超媒体控制 (HATEOAS)
  • 2026 视角:为何级别 3 依然困难?
  • 工程化实践:从设计到部署
  • AI 辅助开发:现代 API 开发工作流
  • 实现方法

URI

统一资源标识符 (URI) 是 Web 技术用于标识 Web 上资源的一串唯一字符序列。在 2026 年,我们设计 URI 时,不仅仅要考虑唯一性,还要考虑到“可预测性”和“AI 友好性”。

你会发现,当你的 URI 结构足够清晰时,像 Cursor 或 GitHub Copilot 这样的 AI 编程助手能更准确地理解你的资源关系,从而生成更精确的代码补全。

HTTP 方法

超文本传输协议 (HTTP) 是一种用于传输超媒体文档的协议。虽然我们都熟悉这些方法,但在生产环境中,正确使用它们的语义往往比看起来要复杂得多。

  • GET: 安全且幂等。我们不仅用它来获取数据,还会利用 INLINECODE2a07bf9b 和 INLINECODEfde6551b 头来实现高效的缓存策略,减少服务器负载。
  • POST: 非幂等。我们通常用于创建子资源或启动一个处理流程。在现代 API 中,POST 也可以用来触发一个复杂的异步任务。
  • PUT: 幂等。我们用它来替换资源的全量表示。切记,如果客户端只传递了部分字段,不要用 PUT,这可能会导致未传递的字段被意外清空。
  • PATCH: 部分更新。这是我们处理资源局部更新的首选,例如仅修改用户的邮箱地址。但要注意处理并发冲突。
  • DELETE: 幂等。用于删除资源。在实际生产中,我们通常实行“软删除”(Soft Delete),即不物理删除数据,而是标记为已删除,以便于数据恢复和审计。

HATEOAS

HATEOAS(超媒体作为应用状态引擎)是 REST 最具争议也最核心的部分。它意味着“可发现性”。客户端可以仅通过服务器的响应与 REST API 进行交互。这是一种自文档化的超媒体。客户端在交互新 API 时无需查阅任何文档(或者文档极少)。

REST 服务根据 Richardson 成熟度模型划分为不同的成熟度级别。 让我们看看你的 API 目前处于哪个阶段。

级别 0:POX 的沼泽

这是最原始的阶段。坦白说,如果你在维护一个遗留系统,你很可能见过这种场景。

特征

  • 使用 HTTP 作为传输协议,但并未利用其特性。
  • 通常依赖单一的端点(例如 POST /api)来处理所有操作。
  • 将 HTTP 视为远程过程调用 (RPC) 的隧道,只是在 HTTP 上包装了 XML 或 JSON。

主要问题

  • 缺乏语义:状态码通常全是 200 OK,错误信息藏在 body 里。
  • 难以缓存:因为一切操作都是 POST,HTTP 缓存中间件完全无法工作。
  • 客户端重:客户端必须“知道”所有的 URL 结构。

级别 1:资源

在这个阶段,我们开始意识到“万物皆资源”。

特征

  • 引入了“资源”的概念作为关键抽象。
  • 资源通过独立的 URL 暴露(例如 INLINECODE010a4d20、INLINECODE0e437205)。

主要问题

虽然 URI 设计得不错,但很多开发者在这个阶段容易犯一个错误:动作滥用。例如,使用 INLINECODE246d2538 而不是 INLINECODEb3e3dbfc。这表明你虽然在处理资源,但还没有充分利用 HTTP 协议的动词。

级别 2:HTTP 动词

这是我们绝大多数“现代化” API 所处的阶段,也是许多开发者认为的“足够好”的阶段。

特征

  • 正确使用 GET、POST、PUT、DELETE。
  • 利用 HTTP 标头进行内容协商(如 Accept: application/json)。
  • 使用标准的状态码(200, 201, 204, 400, 401, 403, 404, 500)。

主要优势

  • 可缓存性:GET 请求可以被网关和浏览器缓存,极大提升性能。
  • 统一接口:一旦前端开发者理解了这套规则,任何新的资源接口都能秒懂。

级别 3:超媒体控制 (HATEOAS)

这是 REST 的“圣杯”。虽然在这个 GraphQL 和 tRPC 大行其道的年代,HATEOAS 看起来有些古老,但在解耦服务端和客户端方面,它依然有着不可替代的优势。

特征

在响应体中,除了数据本身,还包含了下一步可以做什么的链接(Links)。

代码示例:HATEOAS 风格的响应

// 获取用户信息的响应
{
  "id": "u-123",
  "name": "Alex Chen",
  "role": "editor",
  "_links": {
    "self": { "href": "/users/u-123" },
    "update": { "href": "/users/u-123", "method": "PUT" },
    "delete": { "href": "/users/u-123", "method": "DELETE" },
    "articles": { "href": "/users/u-123/articles" }
  },
  "_embedded": {
    "latest_article": {
      "id": "a-999",
      "title": "2026 AI Trends",
      "_links": {
        "self": { "href": "/articles/a-999" }
      }
    }
  }
}

主要优势

  • 解耦:服务端修改 URL 结构时,不需要破坏旧版本的客户端,因为客户端是动态读取链接的。
  • 状态机:API 变成了一个状态机,客户端根据当前状态和提供的链接决定下一步动作,无需硬编码逻辑。

2026 视角:为何级别 3 依然困难?

你可能会问,既然 HATEOAS 这么好,为什么我们在大部分项目中很少见到它?

在我们的经验中,主要原因在于开发范式的不匹配。前端开发者习惯于强类型接口(如 TypeScript 的 interface),他们希望在编写代码时就能获得智能提示。而 HATEOAS 的动态特性使得传统的静态类型检查变得困难。

但是,2026 年的技术栈正在改变这一现状

随着 Agentic AI 的发展,未来的客户端可能不再是由人类硬编码的静态前端代码,而是能够理解超媒体、自主导航 API 的 AI 代理。对于 AI Agent 来说,HATEOAS 是最自然的交互方式——它不需要死记硬背 URL,只需像人类浏览网页一样“点击”链接即可。这使得级别 3 在 AI 原生应用时代迎来了复苏的契机。

工程化实践:从设计到部署

让我们聊聊如何将 RMM 模型应用到实际的工程生产中。我们不仅要设计 API,还要保证它的高可用和可维护性。

1. 生产级代码示例:Level 2 API 实现

我们来看一个使用 Node.js 和 Express 构建的实际例子。我们将展示如何处理内容协商和正确的状态码。

const express = require(‘express‘);
const app = express();
app.use(express.json());

// 模拟数据库
let articles = [{ id: 1, title: ‘RMM Explained‘, content: ‘...‘ }];

// GET /articles - 获取列表 (支持分页)
app.get(‘/api/articles‘, (req, res) => {
  const { page = 1, limit = 10 } = req.query;
  
  // 使用 Set 添加 Link 头,实现简单的分页导航(即使未完全达到 Level 3,这也是个好习惯)
  res.setHeader(‘Link‘, ‘; rel="next"‘);
  
  res.status(200).json({
    data: articles.slice(0, limit),
    meta: { page, limit, total: articles.length }
  });
});

// POST /articles - 创建资源
app.post(‘/api/articles‘, (req, res) => {
  if (!req.body.title) {
    // 使用 400 状态码表示客户端错误
    return res.status(400).json({ error: ‘Title is required‘ });
  }

  const newArticle = {
    id: articles.length + 1,
    title: req.body.title,
    content: req.body.content || ‘‘
  };
  articles.push(newArticle);

  // 使用 201 Created 状态码,并在 Header 中返回 Location
  res.location(`/api/articles/${newArticle.id}`).status(201).json(newArticle);
});

// DELETE /articles/:id - 删除资源
app.delete(‘/api/articles/:id‘, (req, res) => {
  const articleId = parseInt(req.params.id);
  const index = articles.findIndex(a => a.id === articleId);

  if (index === -1) {
    // 404 Not Found 比 200 OK (with success: false) 更符合 HTTP 语义
    return res.status(404).json({ error: ‘Article not found‘ });
  }

  articles.splice(index, 1);
  // 204 No Content 表示操作成功且无返回体
  res.status(204).send();
});

module.exports = app;

2. 故障排查与调试技巧

在我们最近的一个项目中,遇到了一个非常棘手的问题:客户端偶尔报告收到 403 Forbidden,但这并不符合我们的权限逻辑。

排查过程

  • 检查 HTTP 动词:我们发现运维人员在配置 Nginx 反向代理时,错误地拦截了某些 PUT 请求。
  • 监控工具:我们使用了 Grafana Loki 来聚合日志。通过查询 trace_id,我们定位到了是网关层而非应用层返回的错误。

经验总结:在微服务架构中,当你遇到奇怪的 HTTP 状态码时,第一反应不应该是查代码,而是检查网关配置CORS 策略。很多时候,Level 0 或 Level 1 的问题并非来自代码本身,而是基础设施配置不当。

3. 性能优化:HATEOAS 的代价

实现 Level 3 会带来额外的序列化开销。如果你在响应中嵌入了太多关联资源的链接和数据,可能会导致响应体膨胀。

解决方案

  • 字段投影:允许客户端使用 INLINECODE39b8ffa1 参数指定需要的字段(例如 INLINECODE444bd4aa)。
  • 数据分片:不要在 _embedded 中返回所有子资源,只返回摘要或链接。

AI 辅助开发:现代 API 开发工作流

到了 2026 年,如果你还在手写所有的 CRUD 增删改查代码,你可能就落伍了。我们现在的开发流程已经深度融合了 AI 工具,这被称为 Vibe Coding(氛围编程)

使用 Cursor 或 Windsurf 加速开发

当我们需要构建一个新的资源端点时,我们通常这样与 AI 协作:

  • 自然语言定义规范:我们在 IDE 中写下注释:
  •     // Create a RESTful endpoint for /api/orders 
        // Level 2 Maturity: Use GET, POST, PUT, DELETE
        // Implement validation for order status (pending, shipped, delivered)
        // Return proper HTTP status codes
        
  • AI 生成骨架:IDE 自动生成符合我们项目架构(如 NestJS 或 Express)的路由、控制器和验证中间件。
  • Review 与 Refine:我们需要做的只是检查 AI 生成的代码是否符合 Level 2 的语义(比如是否误用了状态码),并调整业务逻辑。

LLM 驱动的测试

我们甚至可以要求 AI 生成边界测试用例。例如,告诉 AI:“测试当库存不足时,INLINECODE8c8a76e6 应该返回 INLINECODE3265b1c2 而不是 500 Error”。AI 能够根据描述生成高质量的集成测试代码,这对于维护 API 的稳定性至关重要。

实现方法

回到基础。为了亲手体验 RMM 的各个层级,我们将创建一个名为 wiki-demo 的 RESTful API。我们将插入文章并发送 HTTP 请求。在此过程中,我们将获取、修改和删除文章。

我们将使用 Robo3T 作为数据库,使用 Postman 发送请求。为了在 Node.js 中创建 RESTful API,我们需要安装以下工具(注:Robo3T 现已更名为 MongoDB Compass,但我们依然习惯这种轻量级的交互):

  • node: 一个 JavaScript 运行时环境,下载链接:https://nodejs.org/en/download/
  • MongoDB Compass/Robo3t: 一个 MongoDB GUI。我们将使用它创建数据库,下载链接:https://www.mongodb.com/try/download/compass
  • Postman: 一个 API 开发和测试平台,下载链接:https://www.postman.com/
  • Visual Studio Code 或 (任何代码编辑器),下载链接:https://code.visualstudio.com/download (推荐安装 Cursor 扩展以体验 AI 辅助)
  • JSON Viewer Pro Chrome 扩展程序,下载链接:https://chromewebstore.google

安装步骤

  • 初始化项目
  •     mkdir wiki-demo-rmm
        cd wiki-demo-rmm
        npm init -y
        npm install express mongoose body-parser
        
  • 启动服务器 (server.js)

让我们编写一个简单的服务器,从 Level 0 演进到 Level 2。

    const express = require(‘express‘);
    const mongoose = require(‘mongoose‘);
    const app = express();
    
    // 连接 MongoDB
    mongoose.connect(‘mongodb://localhost:27017/wiki-demo‘)
      .then(() => console.log(‘MongoDB Connected‘))
      .catch(err => console.error(err));
    
    // 定义 Schema
    const ArticleSchema = new mongoose.Schema({
      title: String,
      content: String
    });
    const Article = mongoose.model(‘Article‘, ArticleSchema);
    
    app.use(express.json());
    
    // Level 2: 定义资源路由
    // GET 获取所有文章
    app.get(‘/articles‘, async (req, res) => {
      const articles = await Article.find();
      res.json(articles);
    });
    
    // POST 创建新文章
    app.post(‘/articles‘, async (req, res) => {
      const newArticle = new Article(req.body);
      await newArticle.save();
      res.status(201).json(newArticle);
    });
    
    // 启动服务
    app.listen(3000, () => {
      console.log(‘Server running on port 3000‘);
    });
    
  • 使用 Postman 测试

– 设置请求为 POST http://localhost:3000/articles

– 在 Body 中选择 INLINECODEd0095e1c 和 INLINECODEc874876a,输入 {"title": "RESTful 2026", "content": "..."}

– 发送请求,你应该会收到 201 Created 响应和创建的对象。

结语:未来展望

Richardson 成熟度模型不仅仅是一个理论工具,它是我们设计 API 时的指南针。虽然大多数系统停留在 Level 2,但了解 Level 3 (HATEOAS) 对于构建真正解耦、面向未来的长期系统至关重要。随着 AI Agent 的普及,那些具备良好超媒体控制的 Level 3 API 将更容易被机器理解和使用。在接下来的文章中,我们将深入探讨如何在 GraphQL 的冲击下,依然保持 REST 的核心竞争力。

让我们一起构建更优雅的 API 吧!

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。如需转载,请注明文章出处豆丁博客和来源网址。https://shluqu.cn/36034.html
点赞
0.00 平均评分 (0% 分数) - 0