4. API 契约设计原则:RESTful 设计原则、资源命名规范、版本控制策略、错误码设计
在微服务架构下,任务调度平台的 API 契约是服务间通信的“法律条文”。一份设计良好的契约不仅能降低集成成本,还能保障系统在长期演进中的稳定性。本章聚焦于 RESTful 设计原则、资源命名规范、版本控制策略与错误码设计四大核心领域,为后续的 OpenAPI 规范落地奠定基础。
4.1 RESTful 设计原则
REST(Representational State Transfer)是一种架构风格,而非严格协议。在任务调度平台中,我们遵循以下六项核心约束:
| 原则 | 说明 | 调度平台示例 |
|---|---|---|
| 客户端-服务器分离 | 关注点分离,前端不关心数据存储,后端不关心 UI | 调度 API 不依赖前端会话状态 |
| 无状态 | 每个请求包含所有必要信息,服务器不保存客户端上下文 | 任务创建请求必须携带完整参数 |
| 可缓存 | 响应隐式或显式标记为可缓存或不可缓存 | 任务列表支持 ETag 缓存 |
| 统一接口 | 资源通过 URI 标识,通过标准方法操作 | 所有任务资源遵循 CRUD 模式 |
| 分层系统 | 客户端无法直接感知是否与端服务器或中间层通信 | API 网关可透明路由到不同调度节点 |
| 按需代码(可选) | 服务器可临时扩展客户端功能 | 动态下发任务执行脚本 |
实践要点:在任务调度场景中,“无状态”是最容易被忽视的原则。例如,分页查询任务历史时,不应依赖服务器端的“当前页码”会话变量,而应由客户端在每次请求中明确传递
page 和 size 参数。
4.2 资源命名规范
资源命名是 API 契约的“门面”。好的命名让开发者无需查阅文档即可理解 API 用途。我们采用以下规范体系:
4.2.1 核心规则
- 使用名词复数形式:
/tasks、/schedules、/executors - 使用小写字母与连字符:
/task-groups、/cron-triggers - 避免动词:用
POST /tasks而非/createTask - 层级关系用斜杠表示:
/tasks/{taskId}/executions - 查询参数用于过滤与排序:
/tasks?status=running&sort=createdAt,desc
4.2.2 任务调度平台资源路径设计
| 资源路径 | HTTP 方法 | 语义 |
|---|---|---|
/tasks |
GET | 获取任务列表 |
/tasks |
POST | 创建新任务 |
/tasks/{taskId} |
GET | 获取单个任务详情 |
/tasks/{taskId} |
PUT | 全量更新任务 |
/tasks/{taskId} |
PATCH | 部分更新任务 |
/tasks/{taskId} |
DELETE | 删除任务 |
/tasks/{taskId}/executions |
GET | 获取任务执行历史 |
/tasks/{taskId}/executions/{execId} |
GET | 获取单次执行详情 |
/tasks/{taskId}/pause |
POST | 暂停任务(动作资源) |
注意:动作资源(如
/pause、/resume)应谨慎使用。优先考虑通过 PATCH /tasks/{taskId} 修改状态字段。仅在需要明确语义分离或触发异步流程时,才使用动作资源。
4.3 版本控制策略
微服务架构下,不同服务可能独立演进。版本控制策略决定了 API 契约的兼容性边界。我们推荐以下三种策略组合使用:
4.3.1 策略对比
| 策略 | 实现方式 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|---|
| URI 路径版本 | /v1/tasks、/v2/tasks |
直观、易于路由 | URL 膨胀、难以维护 | 对外公开 API |
| 请求头版本 | Accept: application/vnd.scheduler.v1+json |
URL 干净、粒度细 | 调试不便、工具支持弱 | 内部服务间调用 |
| 查询参数版本 | /tasks?version=1 |
实现简单 | 缓存混乱、语义模糊 | 临时过渡方案 |
4.3.2 推荐策略:URI 路径版本 + 语义化版本
在任务调度平台中,我们采用 URI 路径版本作为主策略,并配合语义化版本(SemVer)管理内部变更:
- 主版本(Major):不兼容的 API 变更,如删除字段、修改请求结构
- 次版本(Minor):向后兼容的新增功能,如增加可选参数
- 补丁版本(Patch):内部修复,不影响 API 契约
// 示例:版本化请求
GET /v1/tasks/123
Accept: application/json
// 响应中包含 API 版本信息
{
"apiVersion": "1.2.0",
"data": {
"id": "123",
"name": "数据同步任务",
"cron": "0 0 * * *"
}
}
最佳实践:每个 API 响应都应包含
apiVersion 字段,帮助客户端快速确认所调用的版本。同时,在 OpenAPI 规范中,使用 info.version 字段声明当前契约版本。
4.4 错误码设计
统一的错误码体系是 API 契约可调试性的基石。我们设计了一套分层错误码结构,覆盖 HTTP 状态码、业务错误码和详细错误信息。
4.4.1 错误响应结构
{
"error": {
"code": "TASK_NOT_FOUND",
"httpStatus": 404,
"message": "未找到指定的任务资源",
"details": "任务 ID 'invalid-123' 不存在于当前命名空间",
"timestamp": "2025-01-15T10:30:00Z",
"traceId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
}
}
4.4.2 错误码分类表
| 分类 | HTTP 状态码 | 业务错误码示例 | 说明 |
|---|---|---|---|
| 客户端请求错误 | 400 | INVALID_PARAMETER |
请求参数格式错误或缺失 |
| 认证授权错误 | 401 / 403 | UNAUTHORIZED、FORBIDDEN |
身份验证失败或权限不足 |
| 资源未找到 | 404 | TASK_NOT_FOUND、SCHEDULE_NOT_FOUND |
请求的资源不存在 |
| 资源冲突 | 409 | TASK_ALREADY_EXISTS、EXECUTION_IN_PROGRESS |
资源状态冲突,无法执行操作 |
| 频率限制 | 429 | RATE_LIMIT_EXCEEDED |
请求频率超过阈值 |
| 服务端错误 | 500 | INTERNAL_ERROR、SCHEDULER_FAILURE |
服务器内部异常 |
| 服务不可用 | 503 | SERVICE_UNAVAILABLE |
调度服务暂时不可用 |
4.4.3 错误码命名规范
- 使用大写字母与下划线:
INVALID_CRON_EXPRESSION - 前缀标识资源类型:
TASK_、SCHEDULE_、EXECUTOR_ - 错误码应具有唯一性:每个错误码在整个平台中唯一
- 提供可操作的错误信息:
message字段应指导用户如何修正
设计建议:在 OpenAPI 规范中,为每个操作定义
responses 时,至少覆盖 200、400、401、404、500 五种状态码。使用 oneOf 或 discriminator 描述不同错误码对应的响应体结构。
4.5 设计原则全景图
以下 SVG 图展示了 RESTful 设计原则、资源命名、版本控制与错误码设计在任务调度平台中的协同关系:
4.6 本章小结
API 契约设计原则是微服务架构下任务调度平台的“宪法”。通过本章的学习,你应该掌握:
- RESTful 六大原则在调度场景中的具体落地方式
- 资源命名规范如何提升 API 的可读性与一致性
- 版本控制策略的选择依据与语义化版本管理
- 分层错误码体系的设计方法与最佳实践
下一阶段准备:在掌握设计原则后,第 5 章将进入 OpenAPI 规范的具体编写,包括如何将本章的设计原则转化为 YAML/JSON 格式的契约文件,以及如何使用工具进行契约验证与测试。