第二章 RESTful API 设计原则

这一章,我们来聊聊 RESTful API 设计里那些最核心的东西。很多人觉得 REST 就是“URL 漂亮点,用对 GET/POST”,其实不然。

我个人习惯,在设计任何一个 API 之前,先把这三个问题想清楚:资源是什么?怎么命名?动作怎么映射?这三个问题搞定了,剩下的都是细节。

2.1 REST 架构风格的核心概念

REST 不是一个协议,也不是一个标准。它是一种架构风格。说白了,就是一套约束条件,教你如何构建一个分布式、可伸缩的 Web 服务。

这里有几个核心概念,我挑最重要的讲:

  • 资源 (Resource):一切皆资源。用户、订单、令牌()、卡片……都是资源。每个资源都有一个唯一的标识符,就是 URI。
  • 表现层 (Representation):资源在客户端和服务端之间传输的形态。JSON、XML、甚至纯文本都可以。我们做令牌化服务,绝大多数情况用 JSON。
  • 无状态 (Stateless):每个请求都是独立的,服务端不保存客户端上下文。我记得刚入行时,总想把用户登录状态存在 session 里,这在 REST 里是大忌。
  • 统一接口 (Uniform Interface):标准的 HTTP 方法,标准的资源操作。这就是 REST 的“约定优于配置”。

核心要点:REST 的核心是“资源”和“状态转移”。客户端通过操作资源的表现层,来改变服务端资源的状态。你想想看,是不是这个理?

2.2 资源命名规范

给资源起名字,是件挺讲究的事。我见过太多乱七八糟的命名,比如 /getUserInfo、/queryOrderListById,一看就知道是 RPC 风格,不是 REST。

我建议,遵循以下几条原则:

  1. 使用名词,而不是动词。用 /orders,不要用 /getOrders。动词交给 HTTP 方法去表达。
  2. 使用复数形式。集合用复数,比如 /users、/tokens。单个资源用 /users/{userId}。
  3. 用短横线 (-) 分隔,不用下划线 (_) 或驼峰。比如 /payment-methods 比 /payment_methods 或 /paymentMethods 更易读。
  4. 用斜杠 (/) 表示层级关系。比如 /users/{userId}/cards,表示某个用户下的所有卡片。
  5. 用查询参数(Query String)做筛选、排序、分页。比如 /tokens?status=active&page=1&size=20。
正确示例 ✅ 错误示例 ❌ 原因
/tokens/{tokenId} /getTokenById 动词不能出现在路径中
/cards /card 集合资源用复数
/merchants/{id}/transactions /merchant-transactions 用斜杠表示层级,更直观
/users?role=admin /getUsers?role=admin 查询参数不是动词的替代品

避坑指南:我曾经在一个项目中,看到团队把所有 API 都设计成了 /api/v1/doSomething.do 的形式,导致后来无法快速定位资源。从那时起,我就定了个规矩:资源命名,必须一眼能看出它代表什么实体。

2.3 HTTP 方法使用

HTTP 方法,才是 REST 里真正的“动词”。每个方法有它自己的语义和幂等性要求。我整理了一个速查表:

HTTP 方法 语义 幂等性 令牌化服务场景
GET 获取资源 是 查询令牌详情、查询卡片列表
POST 创建资源(或触发非幂等操作) 否 创建新令牌、发起扣款请求
PUT 全量替换资源 是 更新令牌的完整配置
PATCH 局部更新资源 否(需要谨慎设计) 更新令牌的状态(如激活/冻结)
DELETE 删除资源 是 作废一个令牌

个人经验:在设计 POST 创建资源时,我习惯让客户端传入一个 idempotency-key(幂等键)。这样即使客户端重试,也不会重复创建令牌。这是我们后端工程师的“保命符”。

那为什么 PUT 和 PATCH 要区分?

因为语义不同。PUT 是全量覆盖,你传什么,服务端就存什么,没传的字段会被清空。PATCH 是增量更新,只修改你传的字段。嗯,这里要注意:很多团队把 POST 当作万能方法,这是不对的。该用 GET 查,就用 GET;该用 DELETE 删,就别用 POST。

2.4 知识脉络图

下面这张图,把本章的三个核心原则串起来了。从资源抽象开始,到命名规范,再到 HTTP 方法的正确使用,最后落到你的代码里。

RESTful API 设计原则概览 REST 核心概念 • 资源 (Resource) • 表现层 (JSON/XML) • 无状态 (Stateless) 资源命名规范 • 使用名词 (复数) • 短横线 /users/{id} • 斜杠表示层级 HTTP 方法使用 • GET/POST/PUT • PATCH/DELETE • 幂等性 vs 安全性 落地实践:令牌化服务接口设计 /tokens /v1/cards /merchants/{id}/transactions 💡 原则不是教条,而是要解决实际问题。 核心、命名、方法,三者缺一不可。

这套设计原则,说起来简单,写起来全是细节。我自己在深入重构一个老旧支付系统时,就踩过不少坑。但只要你把“资源”这个模型想清楚,命名和方法自然就顺了。