4. 定义 Topic 管理 API:创建、删除与查询
Topic(主题)是消息队列中最核心的命名空间实体,所有消息的发布与订阅都围绕 Topic 进行。本章将基于 OpenAPI 3.0 规范,为 Topic 管理定义三个标准 RESTful 端点:POST /topics(创建)、DELETE /topics/{topicId}(删除)和 GET /topics(查询列表)。我们不仅关注接口的请求/响应结构,更强调错误链路的完整设计,确保客户端能够根据明确的错误码进行精准的异常处理。
4.1 接口概览与契约清单
下表列出了三个核心 Topic 管理接口的 HTTP 方法、路径、主要用途以及预期的成功状态码。所有接口均采用 JSON 作为请求与响应的序列化格式。
| 方法 | 路径 | 用途 | 成功状态码 |
|---|---|---|---|
| POST | /topics |
创建一个新的 Topic | 201 Created |
| DELETE | /topics/{topicId} |
删除指定 ID 的 Topic | 204 No Content |
| GET | /topics |
查询 Topic 列表(支持分页) | 200 OK |
设计原则: 创建操作返回 201 并携带新资源的完整信息;删除操作返回 204 且不包含响应体,符合 RESTful 最佳实践;查询操作返回 200 并封装在标准分页结构中。
4.2 创建 Topic:POST /topics
创建 Topic 是管理入口的第一步。客户端需要提供 Topic 名称、描述以及可选的配置参数。服务端在成功创建后,必须返回完整的 Topic 对象,包括系统生成的唯一 ID 和创建时间戳。
4.2.1 请求体结构
{
"topicName": "order.created",
"description": "订单创建事件主题",
"messageRetentionInHours": 72,
"maxMessageSize": 1048576
}
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
topicName |
string | 是 | Topic 唯一名称,支持字母、数字、下划线和点号 |
description |
string | 否 | Topic 用途描述,最大长度 255 字符 |
messageRetentionInHours |
integer | 否 | 消息保留时长(小时),默认 72 |
maxMessageSize |
integer | 否 | 单条消息最大字节数,默认 1048576(1MB) |
4.2.2 成功响应(201 Created)
{
"topicId": "tp-20250321-abc123",
"topicName": "order.created",
"description": "订单创建事件主题",
"messageRetentionInHours": 72,
"maxMessageSize": 1048576,
"createdAt": "2025-03-21T10:30:00Z",
"status": "ACTIVE"
}
4.2.3 错误响应链路
创建接口可能返回以下错误,客户端应根据 errorCode 进行差异化处理:
| HTTP 状态码 | errorCode | 触发条件 | 建议处理 |
|---|---|---|---|
| 400 | INVALID_TOPIC_NAME |
Topic 名称格式不合法或为空 | 提示用户修改名称 |
| 409 | TOPIC_ALREADY_EXISTS |
同名 Topic 已存在 | 提示用户使用其他名称 |
| 422 | INVALID_RETENTION |
保留时长超出系统限制(1~720 小时) | 提示用户调整参数 |
| 429 | RATE_LIMIT_EXCEEDED |
创建频率超过配额 | 客户端退避重试 |
注意: 409 冲突错误与 422 参数错误在语义上有明确区分。前者表示资源已存在,后者表示请求参数本身不合法。客户端不应将 409 视为参数错误。
4.3 删除 Topic:DELETE /topics/{topicId}
删除操作需要指定 Topic 的唯一 ID。由于删除是不可逆操作,服务端必须进行严格的权限校验和资源状态检查。成功删除后返回 204,不包含响应体。
4.3.1 路径参数
| 参数 | 位置 | 类型 | 说明 |
|---|---|---|---|
topicId |
path | string | Topic 的唯一标识符,例如 tp-20250321-abc123 |
4.3.2 错误响应链路
删除接口的错误处理需要覆盖资源不存在、资源被占用以及内部状态异常等场景:
| HTTP 状态码 | errorCode | 触发条件 | 建议处理 |
|---|---|---|---|
| 404 | TOPIC_NOT_FOUND |
指定的 topicId 不存在 | 检查 topicId 是否正确 |
| 409 | TOPIC_HAS_SUBSCRIPTIONS |
该 Topic 下存在活跃订阅者 | 先删除所有订阅再重试 |
| 409 | TOPIC_HAS_PENDING_MESSAGES |
Topic 中仍有未消费的消息 | 等待消息消费完毕或强制清空 |
| 500 | INTERNAL_DELETE_ERROR |
后端存储删除操作失败 | 记录错误并联系运维 |
关键设计: 删除接口的 409 错误包含两种不同子类型。客户端应优先检查
errorCode 字段,而不是仅依赖 HTTP 状态码。例如,TOPIC_HAS_SUBSCRIPTIONS 需要用户手动干预,而 TOPIC_HAS_PENDING_MESSAGES 可能通过等待自动解决。
4.4 查询 Topic 列表:GET /topics
列表查询接口支持分页和可选的名称模糊搜索。响应体采用标准的分页封装,包含当前页数据、总记录数以及分页元信息。
4.4.1 查询参数
| 参数 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
pageSize |
integer | 否 | 20 | 每页返回的记录数,最大 100 |
pageToken |
string | 否 | — | 分页令牌,首次请求不传,后续从响应中获取 |
nameFilter |
string | 否 | — | 按 Topic 名称前缀模糊搜索 |
4.4.2 成功响应(200 OK)
{
"topics": [
{
"topicId": "tp-20250321-abc123",
"topicName": "order.created",
"description": "订单创建事件主题",
"status": "ACTIVE",
"createdAt": "2025-03-21T10:30:00Z"
},
{
"topicId": "tp-20250321-def456",
"topicName": "payment.success",
"description": "支付成功事件主题",
"status": "ACTIVE",
"createdAt": "2025-03-21T11:00:00Z"
}
],
"nextPageToken": "eyJsYXN0SWQiOiJ0cC0yMDI1MDMyMS1kZWY0NTYifQ==",
"totalCount": 42
}
4.4.3 错误响应链路
| HTTP 状态码 | errorCode | 触发条件 | 建议处理 |
|---|---|---|---|
| 400 | INVALID_PAGE_SIZE |
pageSize 超出 1~100 范围 | 修正 pageSize 参数 |
| 400 | INVALID_PAGE_TOKEN |
pageToken 格式错误或已过期 | 重新从第一页开始请求 |
| 500 | INTERNAL_LIST_ERROR |
后端查询异常 | 记录错误并联系运维 |
4.5 错误处理链路全景图
下面的 SVG 图展示了三个 Topic 管理接口的完整错误处理链路,包括客户端发起请求、服务端校验、业务逻辑处理以及错误响应的标准化流程。
4.6 标准化错误响应体设计
所有错误响应必须遵循统一的 JSON 结构,确保客户端可以基于 errorCode 字段进行编程式处理,而不是解析文本消息。
{
"error": {
"code": "TOPIC_ALREADY_EXISTS",
"message": "Topic 'order.created' already exists.",
"details": {
"existingTopicId": "tp-20250321-abc123",
"conflictField": "topicName"
},
"requestId": "req-7a1b2c3d-4e5f-6789-abcd-ef0123456789",
"timestamp": "2025-03-21T10:30:05Z"
}
}
| 字段 | 类型 | 说明 |
|---|---|---|
error.code |
string | 机器可读的错误码,用于客户端逻辑分支 |
error.message |
string | 人类可读的错误描述,支持国际化 |
error.details |
object | 可选字段,提供额外的上下文信息 |
error.requestId |
string | 请求追踪 ID,用于日志关联和排查 |
error.timestamp |
string | 错误发生时间(ISO 8601 格式) |
最佳实践: 在 OpenAPI 规范中,建议将错误响应体定义为可复用的
$ref 组件(例如 #/components/schemas/ErrorResponse),并在所有接口的 4xx 和 5xx 响应中引用该组件,确保契约的一致性。
4.7 本章小结
Topic 管理 API 的设计核心在于三点:
- 资源语义清晰: 创建返回 201 + 完整资源,删除返回 204 无响应体,查询返回 200 + 分页结构。
- 错误码精细化: 每个错误场景都有唯一的
errorCode,客户端可以根据 code 而非 message 做决策。 - 错误体标准化: 统一的 JSON 结构包含 code、message、details、requestId 和 timestamp,便于日志追踪和自动化处理。