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。
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 语义,增加客户端解析成本。
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 发生不兼容变更时(如删除字段、修改必填项、变更响应结构),必须提升主版本号。兼容性变更(如新增可选字段)无需升级版本。