2. API设计规范基础
RESTful API 设计规范是微服务间契约的“语法书”。一套清晰、一致的规范能大幅降低服务提供方与消费方之间的理解偏差,为后续的契约测试与 Mock 隔离奠定基础。本节将围绕四大核心维度展开:设计原则、资源命名、方法语义与状态码规范。
2.1 RESTful 六大设计原则
REST(Representational State Transfer)并非协议,而是一组架构约束。遵循这些原则的 API 才具备“RESTful”属性。
| 原则 | 核心要求 | 常见反例 |
|---|---|---|
| 客户端-服务端分离 | 关注点分离,客户端不关心数据存储,服务端不关心 UI | 在 API 响应中嵌入 HTML 片段 |
| 无状态 | 每个请求包含所有必要信息,服务端不保存客户端上下文 | 依赖 Session 或服务端缓存的上一次请求状态 |
| 可缓存 | 响应隐式或显式标记为可缓存或不可缓存 | 所有 GET 请求均返回 Cache-Control: no-store |
| 统一接口 | 资源标识、资源操作、自描述消息、HATEOAS | 使用 /getUser?id=1 而非 /users/1 |
| 分层系统 | 客户端无法直接区分是与最终服务端还是中间件通信 | 在 API 路径中暴露网关或代理信息 |
| 按需代码(可选) | 服务端可临时传输可执行代码扩展客户端功能 | 强制要求客户端执行远程脚本 |
实践要点:在微服务架构中,“统一接口”与“无状态”是最容易被忽视的两条原则。无状态是水平扩展的前提,统一接口是契约测试能够自动化的基础。
2.2 资源命名规范
资源是 RESTful API 的核心抽象。命名规范直接影响 API 的可读性与可维护性。
2.2.1 核心规则
- 使用名词复数形式:
/users而非/user,/orders而非/getOrder。 - 使用小写字母与连字符:
/order-items而非/orderItems或/order_items。 - 避免动词:操作由 HTTP 方法表达,路径中不应出现
/createUser、/deleteOrder。 - 层级关系用斜杠表示:
/users/{userId}/orders/{orderId}。 - 查询参数用于过滤与排序:
/orders?status=active&sort=created_at。
2.2.2 常见资源模式
| 模式 | 示例 | 说明 |
|---|---|---|
| 集合资源 | GET /users |
返回用户列表 |
| 单例资源 | GET /users/{id} |
返回单个用户 |
| 子资源 | GET /users/{id}/orders |
用户的订单列表 |
| 关联资源 | GET /orders/{id}/items |
订单下的商品明细 |
| 操作资源(RPC 风格) | POST /payments/{id}/refund |
仅在标准 CRUD 无法表达时使用 |
避坑提示:避免在路径中使用动词+名词混合,如
/api/v1/getUserOrders。正确的做法是 GET /users/{userId}/orders。路径只描述“是什么”,方法描述“做什么”。
2.3 HTTP 方法语义化
每个 HTTP 方法在 RESTful 架构中都有明确的语义。方法的选择必须与操作类型严格对应。
| 方法 | 语义 | 幂等 | 安全 | 请求体 | 响应体 |
|---|---|---|---|---|---|
| GET | 获取资源 | 是 | 是 | 无 | 资源表示 |
| POST | 创建资源 / 触发操作 | 否 | 否 | 创建数据 | 新资源或操作结果 |
| PUT | 全量替换资源 | 是 | 否 | 完整资源 | 更新后的资源 |
| PATCH | 部分更新资源 | 否 | 否 | 差异数据 | 更新后的资源 |
| DELETE | 删除资源 | 是 | 否 | 无 | 无(204) |
| HEAD | 获取响应头(无体) | 是 | 是 | 无 | 仅头部 |
| OPTIONS | 获取支持的 HTTP 方法 | 是 | 是 | 无 | Allow 头部 |
关键区分:PUT 与 PATCH 的差异常被忽略。PUT 要求客户端发送完整的资源表示,缺失的字段应被置空;PATCH 只发送需要修改的字段。在契约测试中,这两种方法的请求体结构差异很大,必须明确约定。
2.4 状态码使用规范
状态码是 API 响应语义的重要组成部分。合理使用状态码能让客户端无需解析响应体即可判断请求结果。
2.4.1 常用状态码分类
| 分类 | 范围 | 典型场景 |
|---|---|---|
| 2xx 成功 | 200–206 | 请求被正常处理 |
| 3xx 重定向 | 300–307 | 资源位置变更 |
| 4xx 客户端错误 | 400–451 | 请求格式、权限、资源不存在 |
| 5xx 服务端错误 | 500–511 | 服务内部故障、网关超时 |
2.4.2 推荐状态码映射
| 场景 | 推荐状态码 | 说明 |
|---|---|---|
| GET 成功 | 200 OK | 返回资源表示 |
| POST 创建成功 | 201 Created | 返回 Location 头部指向新资源 |
| PUT/PATCH 更新成功 | 200 OK | 返回更新后的资源 |
| DELETE 删除成功 | 204 No Content | 无响应体 |
| 请求体格式错误 | 400 Bad Request | JSON 解析失败、字段校验不通过 |
| 未认证 | 401 Unauthorized | 缺少或无效的认证凭据 |
| 无权限 | 403 Forbidden | 认证通过但无操作权限 |
| 资源不存在 | 404 Not Found | 路径或资源 ID 无效 |
| 请求冲突 | 409 Conflict | 资源状态冲突(如重复创建) |
| 请求过多 | 429 Too Many Requests | 限流触发 |
| 服务内部错误 | 500 Internal Server Error | 未捕获的异常 |
| 服务不可用 | 503 Service Unavailable | 熔断、过载、维护中 |
常见错误:不要将所有错误都返回 400 或 500。例如,资源不存在应返回 404,而非 400;认证失败应返回 401,而非 403。错误的状态码会误导客户端处理逻辑,进而导致契约测试误判。
2.5 规范全景图:从原则到实践
下图展示了 RESTful API 设计规范从顶层原则到底层实现的全景关系,帮助理解各要素之间的依赖与协作。
2.6 规范落地检查清单
在团队推行 API 设计规范时,可使用以下清单进行评审与自检:
- 路径是否仅包含名词? 检查是否有
/getUsers、/deleteOrder等动词路径。 - 是否使用复数形式? 统一使用
/users而非/user。 - 层级关系是否用斜杠表达? 如
/users/{id}/orders而非/orders?userId={id}。 - HTTP 方法是否与操作语义匹配? 创建用 POST,查询用 GET,全量更新用 PUT,部分更新用 PATCH,删除用 DELETE。
- 状态码是否准确反映结果? 成功创建用 201,删除成功用 204,资源不存在用 404,服务故障用 500。
- 响应体是否包含自描述信息? 错误响应应包含
error字段与message说明。 - 是否遵循无状态约束? 请求中是否携带了必要的认证与上下文信息?
推荐实践:将上述检查清单集成到 API 设计评审流程中,并在 CI 阶段使用 OpenAPI 规范校验工具(如 Spectral)自动检查命名与方法语义的合规性。这是从“人工评审”迈向“自动化治理”的第一步。