💡 Key Takeaways
- The Foundation: Understanding REST Beyond the Buzzword
- Principle 1: Resources Are Nouns, Not Verbs
- Principle 2: HTTP Methods Mean What They Mean
- Principle 3: Status Codes Are Your Communication Protocol
作为一家金融科技独角兽的首席 API 架构师,三年后我在向投资者演示产品时,目睹我们的移动应用程序显著崩溃。罪魁祸首是一个返回 47MB JSON 的 API 端点,因为有人认为“更多数据总是更好”。这个令人尴尬的时刻——以及它造成的 200 万美元资金延迟——让我明白 API 设计不仅仅是让它们正常工作。它还关乎在规模上优雅、可预测和可持续地实现功能。
💡 关键要点
- 基础:超越流行语理解 REST
- 原则 1:资源是名词,不是动词
- 原则 2:HTTP 方法的意思是它们的意思
- 原则 3:状态码是你的通信协议
我叫马库斯·陈,过去 12 年来我设计的 API 处理了从每天 50 个请求到 5000 万个请求的所有事务。我见过出色的工程师创建如此复杂的 API,以至于即使他们自己六个月后都不记得如何使用它们。我还见过初级开发人员设计出如此直观的接口,以至于文档几乎变得不必要。区别在于对超越框架、语言和架构趋势的基本原则的承诺。
我将分享指导我构建的每个成功 API 的 10 条原则——这些原则是通过生产事故、用户反馈和无数次代码评审锻造而成。这些不是理论理想;它们是经过实战检验的指导方针,节省了我团队数百小时,避免了无数集成头痛。
基础:超越流行语理解 REST
在深入具体原则之前,让我们先面对一个不舒服的真相:大多数“REST API”实际上并不是 RESTful。它们是带有 JSON 响应的 HTTP API,这很好,但称它们为 REST 就像把自行车称为摩托车,因为它们都有轮子。罗伊·费尔丁的原始 REST 论文概述了六个约束,而大多数 API 至少违反了其中三个。
实践中重要的是:REST 是一种架构风格,将 API 视为资源集合,每个资源由 URL 识别,通过标准的 HTTP 方法进行操作。这种方法的美在于其可预测性。当我看到 GET /users/123 时,我知道它的具体作用,而无需阅读文档。当我看到 POST /users 时,我知道它是在创建一个新用户。这种一致性是 REST 的超级能力。
根据我的经验,真正理解 REST 原则的团队可以比将其视为检查框的团队快 40% 发布 API。为什么?因为 REST 提供了一种指导设计决策的思维模型。这个应该是新端点还是查询参数?REST 能给出答案。这个应该是 POST 还是 PUT?REST 会告诉你。这些原则不是约束——它们是保护栏,让你保持在可维护、可扩展的 API 之路上。
在我的职业生涯中,我审查了超过 200 个 API 设计,而那些经受住时间考验的设计都共享一个特征:它们尊重 REST 的资源导向思维。那些变成维护噩梦的设计?它们将 REST 视为建议,而不是框架。你的 API 的生命周期比你预期的要长——在生产中可能至少 5-7 年。以这种持久性为目标进行设计。
原则 1:资源是名词,不是动词
这个原则看起来显而易见,但在现实世界中却常常被违反。我曾经继承过一个 API,其端点如 /getUser、/createOrder 和 /deleteProduct。每个操作在 URL 中都是一个动词,使得 HTTP 方法显得多余。这个 API 有 127 个端点,而 23 个基于资源的端点就能做得更好。
规则是:你的 URL 应该表示事物(资源),而 HTTP 方法应该表示对这些事物的操作。与其使用 POST /createUser,不如使用 POST /users。与其使用 GET /getUserOrders,不如使用 GET /users/123/orders。这不是迂腐——这关乎创建一种可扩展的一致思维模型。
考虑认知负担。使用动词型 URL,开发人员必须记住任意的端点名称。使用基于资源的 URL,他们遵循一种模式。在我们的金融科技应用程序中,我们通过重构为适当的资源命名,将新开发者的入职时间从 3 周缩短到了 1.5 周。这个 API 变得自我文档。
当然,也有例外。不适合精确符合 CRUD 操作的操作——如 POST /payments/123/refund 或 POST /orders/456/cancel——是可以接受的。这些是控制器样式的端点,当替代方案显得笨拙时,它们是合理的。关键是要少用并保持一致。在我们当前的 API 中,89% 的端点是纯资源操作,剩下的 11% 则是清晰文档化的控制器操作。
命名资源时,始终使用复数名词。/users 而不是 /user,/orders 而不是 /order。是的,GET /users/123 返回一个单一用户,这在语法上可能会感到奇怪,但一致性胜于语法。我见过团队浪费数小时争论单数与复数;选择复数并继续前进即可。
原则 2:HTTP 方法的意思是它们的意思
HTTP 为我们提供了丰富的词汇:GET、POST、PUT、PATCH、DELETE 等等。每个都有特定的含义,尊重这些含义使你的 API 可预测并可缓存。然而,我经常看到 API 使用 POST 做所有事情——创建、更新、删除,甚至检索数据。这就像用锤子完成所有木工任务,因为你不想学习其他工具。
| 方法 | 响应大小 | 网络效率 | 客户端复杂性 |
|---|---|---|---|
| 返回所有 | 每个请求 47MB 以上 | 差 - 大量开销 | 低 - 但浪费 |
| 仅分页 | 可变,无法控制 | 中等 - 仍然过量获取 | 低 - 实现简单 |
| 字段过滤 | 客户端控制 | 良好 - 获取所需内容 | 中等 - 需要查询参数 |
| GraphQL 替代方案 | 精确控制 | 优秀 - 零过量获取 | 高 - 学习曲线 |
| 智能默认 + 扩展 | 优化的基线 | 优秀 - 平衡的方法 | 低 - 对大多数情况直观 |
GET 请求必须是安全和幂等的。安全意味着它们不会修改服务器状态。幂等意味着多次调用它们会产生相同的结果。这不是学术问题——它使得缓存成为可能,从而可以将你读重的 API 的服务器负担减少 60-80%。当我通过正确实施 GET 语义和 HTTP 缓存来优化我们的用户档案 API 时,我们的服务器成本降低了每月 4200 美元。
POST 创建新资源。它既不是安全的,也不是幂等的——调用两次会创建两个资源。PUT 替换整个资源,并且是幂等的——调用十次的效果与调用一次相同。PATCH 部分更新资源,应是幂等的。DELETE 删除一个资源,并且是幂等的。这些区别对于客户端重试逻辑、缓存策略和 API 网关配置都很重要。
这是我们支付处理 API 的一个实际例子。我们最初为所有操作使用 POST,包括支付状态检查。当网络问题导致客户端重试请求时,我们创建了重复的支付记录。经过重构,使用 GET 进行状态检查并为POST 请求实施合适的幂等性键后,重复支付比例从 2.3% 降低到 0.01%。这是真实存钱和客户信任的维持。
一个常见的问题是:何时使用 PUT 和 PATCH?当客户端发送完整资源表示时使用 PUT。当客户端仅发送要更改的字段时使用 PATCH。在实际中,PATCH 通常更合适,因为客户端很少希望发送每个字段。我们的分析数据显示,94% 的更新操作使用 PATCH,这使我们的移动应用通过平均减少 73% 的有效载荷大小变得更加高效。
原则 3:状态码是你的通信协议
HTTP 状态码是一种标准化的语言,用于沟通...