3. API 设计基础:RESTful 设计规范、资源建模、HTTP 方法语义、状态码选择

RESTful API 是当前微服务架构中最主流的交互范式。本章从 资源建模、HTTP 方法语义、状态码选择 三个核心维度,结合领域驱动设计中的聚合与实体概念,讲解如何设计出语义清晰、可治理的 API 边界。

3.1 资源建模:从领域实体到 URI 设计

资源是 REST 架构的核心抽象。资源建模的第一步是将领域模型中的聚合根和实体映射为 URI 路径,将值对象或子资源映射为嵌套路径或查询参数。

领域概念 URI 示例 说明
聚合根(订单) /orders 资源集合,复数名词
具体实体 /orders/{orderId} 单一资源,路径参数标识
子资源(订单项) /orders/{orderId}/items 从属集合,不可独立于父资源
值对象(地址) /orders/{orderId}/shipping-address 单一子资源,通常不可单独增删
跨聚合查询 /orders?status=paid&customerId=123 查询参数用于过滤、排序、分页
命名规范:URI 路径统一使用小写字母、连字符(-)分隔单词,禁止使用下划线或驼峰。例如 /shipping-address 而非 /shippingAddress 或 /shipping_address。
资源建模与 URI 层级关系 资源建模与 URI 层级关系 /orders /orders/{id} /orders?status= /orders/batch /orders/{id}/items /orders/{id}/status /orders/{id}/items/{itemId} 说明:聚合根映射为集合资源,子资源通过路径嵌套表达从属关系,查询参数用于过滤和分页。

3.2 HTTP 方法语义与幂等性

每个 HTTP 方法在 RESTful API 中都有明确的语义约定。正确使用方法语义是 API 可治理性的基础,尤其要关注幂等性和安全性。

HTTP 方法 CRUD 语义 幂等 安全 请求体 响应体
GET 读取资源 ✅ 是 ✅ 是 无 资源表示
POST 创建资源 / 触发操作 ❌ 否 ❌ 否 创建内容 201 + Location
PUT 全量替换资源 ✅ 是 ❌ 否 完整资源 200 或 204
PATCH 部分更新资源 ❌ 否* ❌ 否 增量变更 200 或 204
DELETE 删除资源 ✅ 是 ❌ 否 无 204
幂等性陷阱:PATCH 方法在 JSON Merge Patch 语义下是幂等的,但在 JSON Patch(RFC 6902)语义下可能非幂等。设计时应在 API 文档中明确声明 PATCH 的幂等性保证。

3.3 状态码选择:精确表达处理结果

状态码是 API 响应语义的重要组成部分。选择正确的状态码可以减少客户端对响应体的依赖,提升调用方对错误类型的快速识别能力。

3.3.1 成功类状态码

状态码 含义 典型场景
200 OK 请求成功,响应体包含资源 GET 查询、PUT 全量更新
201 Created 资源创建成功 POST 创建资源,返回 Location 头
204 No Content 请求成功,无响应体 DELETE 删除、部分 PATCH 成功

3.3.2 客户端错误类状态码

状态码 含义 典型场景
400 Bad Request 请求格式错误或参数校验失败 缺少必填字段、JSON 解析失败
401 Unauthorized 未提供或提供了无效的身份凭证 Token 缺失、过期或签名错误
403 Forbidden 身份认证通过,但无操作权限 角色不足、资源访问受限
404 Not Found 请求的资源不存在 URI 路径错误、资源已被删除
409 Conflict 资源当前状态与请求冲突 版本冲突、唯一约束违反
422 Unprocessable Entity 请求体语义正确但业务规则校验失败 订单金额超限、库存不足
429 Too Many Requests 请求频率超过限流阈值 API 限流触发,返回 Retry-After 头

3.3.3 服务端错误类状态码

状态码 含义 典型场景
500 Internal Server Error 服务器内部未预期错误 数据库连接失败、空指针异常
502 Bad Gateway 上游服务返回无效响应 网关无法从下游服务获取有效数据
503 Service Unavailable 服务暂时不可用(通常可恢复) 服务熔断、过载保护、维护中
504 Gateway Timeout 上游服务响应超时 下游服务处理时间超过网关超时阈值
常见反模式:不要对所有错误都返回 400 或 500。例如业务校验失败应使用 422,权限不足应使用 403,资源不存在应使用 404。统一返回 200 + 业务错误码会破坏 HTTP 语义,增加客户端解析成本。
状态码选择决策流程 状态码选择决策流程 收到 API 请求 格式正确? 400 认证通过? 401 执行业务逻辑 说明:先校验请求格式(400),再校验认证(401),最后执行业务逻辑。业务逻辑中的权限不足返回 403,资源不存在返回 404。

3.4 响应体结构规范

统一的响应体结构可以降低客户端解析成本。建议为成功响应和错误响应分别定义标准格式。

3.4.1 成功响应结构

{
  "data": { ... },           // 核心资源数据
  "meta": {                  // 元数据(可选)
    "page": 1,
    "pageSize": 20,
    "total": 156
  }
}

3.4.2 错误响应结构

{
  "error": {
    "code": "ORDER_AMOUNT_EXCEEDS_LIMIT",
    "message": "订单金额超出单笔限额",
    "details": {
      "maxAmount": 50000,
      "currentAmount": 65000
    },
    "traceId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
  }
}
traceId 的重要性:在微服务架构中,每个 API 响应都应携带 traceId,便于在分布式链路追踪系统中快速定位问题。错误响应中的 traceId 是开发者和运维人员排查问题的关键入口。

3.5 版本管理策略

API 版本管理是治理事务边界的重要环节。推荐使用 URI 路径版本 作为主要版本策略,配合 请求头版本 做细粒度兼容。

策略 示例 适用场景
URI 路径版本 /v1/orders 主版本号变更,不兼容升级
请求头版本 Accept: application/vnd.myapi.v2+json 同一 URI 多版本共存,细粒度控制
查询参数版本 /orders?version=2 临时兼容,不推荐长期使用
治理建议:每个 API 在发布时即确定主版本号,版本号与 Git Tag 对齐。当 API 发生不兼容变更时(如删除字段、修改必填项、变更响应结构),必须提升主版本号。兼容性变更(如新增可选字段)无需升级版本。