Files
team-api/docs/reference/api-format-reference.md
T

262 lines
9.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# API 接口格式参考
本文档是 CLAUDE.md 中 API 接口规范的详细参考资料,包含完整的 JSON 示例、响应格式、错误类型映射等。开发时按需查阅。
## 统一响应格式详细示例
**适用范围**:`/api/admin/*`、`/api/tenant/*`、`/api/payment/*`、`/api/open/*`、`/api/status`。
### 字段说明
| 字段 | 类型 | 说明 |
|------|------|------|
| `code` | int | `0` = 成功,非 `0` = 错误。标准 HTTP 错误直接用状态码(400/401/403/404/409/500),业务错误用 >= 10000 的自定义码 |
| `message` | string | 用户可读的中文提示。成功时固定 `"ok"`,错误时描述具体原因,禁止暴露技术细节 |
| `data` | any | 成功时为业务数据(对象/数组/字符串),错误时为 `null` |
| `request_id` | string | 每个请求的唯一标识,贯穿全链路,用于日志追踪 |
### 响应示例
```json
// 成功(HTTP 200)
{"code": 0, "message": "ok", "data": {"id": 1, "name": "张三"}, "request_id": "req_abc123"}
// 参数错误(HTTP 400)
{"code": 400, "message": "用户名不能为空", "data": null, "request_id": "req_def456"}
// 业务错误(HTTP 422)
{"code": 10001, "message": "余额不足", "data": null, "request_id": "req_ghi789"}
```
### data 字段格式规范
| 接口类型 | data 结构 | 示例 |
|----------|----------|------|
| 分页列表 | `{list, total, page, page_size}` | `{"list": [...], "total": 100, "page": 1, "page_size": 20}` |
| 不分页列表 | `{list}` | `{"list": [...]}` |
| 创建资源 | `{id}` | `{"id": 42}` |
| 资源详情 | 直接返回对象 | `{"id": 1, "name": "张三", ...}` |
| 更新/删除 | `null` | `null` |
**规则**:
- 列表数据的数组字段名统一用 `list`,禁止使用 `data`、`items`、`records` 等其他名称
- 分页列表必须返回 `total`(总条数)和 `page`(当前页码),可选返回 `page_size`
- 创建操作只返回新资源的 `id`,不返回完整对象
- 更新/删除操作返回 `null`,前端通过 HTTP 200 + `code: 0` 判断成功
- 如果 list 内部可以为空,但是不能有 null 出现
### HTTP 状态码映射规则
| 业务场景 | HTTP 状态码 | code 值 | 说明 |
|----------|------------|---------|------|
| 成功 | 200 | `0` | 请求处理成功 |
| 参数校验失败 | 400 | `400` | 请求体格式错误、必填字段缺失、值不合法 |
| 未认证 | 401 | `401` | Token 缺失、过期、无效 |
| 无权限 | 403 | `403` | 已认证但无权访问该资源 |
| 资源不存在 | 404 | `404` | 查询的对象不存在 |
| 请求频率超限 | 429 | `429` | 触发限流 |
| 业务规则错误 | 422 | `>= 10000` | 业务逻辑不满足,使用自定义错误码(见 `consts.go`) |
| 服务器内部错误 | 500 | `500` | 未预期的异常 |
### 业务错误码定义(>= 10000)
业务错误码定义在 `internal/consts/consts.go` 中,每个错误码有对应的中文消息常量。新增业务错误时必须同时在 `consts.go` 中添加 `Code` 和 `Msg` 常量。
| 错误码 | 常量名 | 默认消息 |
|--------|--------|---------|
| 10001 | `CodeInsufficientBalance` | 余额不足 |
| 10002 | `CodeQuotaExceeded` | 额度已用完 |
| 10003 | `CodeChannelUnavailable` | 没有可用的渠道 |
| ... | 更多见 `consts.go` | ... |
## 大模型代理接口格式(`/v1/*`、`/v1beta/*`、`/suno/*`)
### 已注册的代理端点
| 方法 | 路径 | 功能 | 请求格式 | 流式支持 |
|------|------|------|---------|---------|
| POST | `/v1/chat/completions` | Chat Completions | OpenAI | SSE |
| POST | `/v1/completions` | Text Completions | OpenAI | SSE |
| POST | `/v1/embeddings` | 文本向量 | OpenAI | 否 |
| POST | `/v1/images/generations` | 图像生成 | OpenAI | 否 |
| POST | `/v1/images/edits` | 图像编辑 | OpenAI | 否 |
| POST | `/v1/messages` | Claude Messages | Claude | SSE |
| POST | `/v1/responses` | OpenAI Responses | OpenAI | SSE |
| POST | `/v1/audio/speech` | 语音合成 | OpenAI | 否 |
| POST | `/v1/audio/transcriptions` | 语音转文字 | OpenAI | 否 |
| POST | `/v1/audio/translations` | 语音翻译 | OpenAI | 否 |
| POST | `/v1/rerank` | 重排序 | OpenAI | 否 |
| POST | `/v1/moderations` | 内容审核 | OpenAI | 否 |
| GET | `/v1/models` | 模型列表 | — | 否 |
| GET | `/v1/models/{model_id}` | 模型详情 | — | 否 |
| GET | `/v1/realtime` | 实时对话(WebSocket) | OpenAI | WebSocket |
| POST | `/v1/video/generations` | 视频生成(异步任务) | 自定义 | 否 |
| GET | `/v1/video/generations/{task_id}` | 视频生成任务查询 | — | 否 |
| GET | `/v1beta/models` | Gemini 模型列表 | Gemini | 否 |
| GET | `/v1beta/models/{model}` | Gemini 模型详情 | Gemini | 否 |
| POST | `/v1beta/models/{model}` | Gemini 内容生成 | Gemini | SSE |
| POST | `/suno/submit/{action}` | Suno 音乐生成提交 | 自定义 | 否 |
| POST | `/suno/fetch` | Suno 批量查询 | 自定义 | 否 |
| GET | `/suno/fetch/{task_id}` | Suno 任务查询 | — | 否 |
### OpenAI 格式端点响应
**非流式响应**直接透传上游 JSON,典型结构:
```json
// Chat Completions 响应
{
"id": "chatcmpl-abc123",
"object": "chat.completion",
"created": 1677652288,
"model": "gpt-4o",
"choices": [
{
"index": 0,
"message": {"role": "assistant", "content": "Hello!"},
"finish_reason": "stop"
}
],
"usage": {
"prompt_tokens": 9,
"completion_tokens": 12,
"total_tokens": 21
}
}
```
```json
// Embeddings 响应
{
"object": "list",
"data": [
{"object": "embedding", "embedding": [0.1, 0.2, ...], "index": 0}
],
"model": "text-embedding-3-small",
"usage": {"prompt_tokens": 5, "total_tokens": 5}
}
```
**流式响应**使用 SSE(Server-Sent Events),`Content-Type: text/event-stream`:
```
data: {"id":"chatcmpl-abc123","object":"chat.completion.chunk","created":1677652288,"model":"gpt-4o","choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":null}]}
data: {"id":"chatcmpl-abc123","object":"chat.completion.chunk","created":1677652288,"model":"gpt-4o","choices":[{"index":0,"delta":{"content":"Hello"},"finish_reason":null}]}
data: {"id":"chatcmpl-abc123","object":"chat.completion.chunk","created":1677652288,"model":"gpt-4o","choices":[{"index":0,"delta":{},"finish_reason":"stop"}],"usage":{"prompt_tokens":9,"completion_tokens":12,"total_tokens":21}}
data: [DONE]
```
**OpenAI 格式错误响应**:
```json
{
"error": {
"type": "invalid_request_error",
"message": "余额不足,请联系管理员充值",
"param": null,
"code": null
}
}
```
**错误类型映射**:
| 平台错误场景 | error.type | HTTP 状态码 |
|-------------|-----------|------------|
| 认证失败(API Key 无效) | `authentication_error` | 401 |
| 权限不足(Key 无权访问模型) | `permission_error` | 403 |
| 余额不足 / 额度耗尽 | `insufficient_quota` | 402 |
| 模型不存在 / 参数错误 | `invalid_request_error` | 400 |
| 请求频率超限 | `rate_limit_error` | 429 |
| 没有可用渠道 | `server_error` | 503 |
| 上游供应商错误 | 原样透传上游错误类型 | 上游状态码 |
| 平台内部错误 | `internal_error` | 500 |
### Claude 格式端点响应(`/messages`)
**非流式响应**:
```json
{
"id": "msg_abc123",
"type": "message",
"role": "assistant",
"content": [{"type": "text", "text": "Hello!"}],
"model": "claude-sonnet-4-20250514",
"stop_reason": "end_turn",
"usage": {
"input_tokens": 25,
"output_tokens": 10
}
}
```
**流式响应(SSE)**:
```
event: message_start
data: {"type":"message_start","message":{"id":"msg_abc123","type":"message","role":"assistant","content":[],"model":"claude-sonnet-4-20250514","usage":{"input_tokens":25,"output_tokens":0}}}
event: content_block_delta
data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"Hello!"}}
event: message_delta
data: {"type":"message_delta","delta":{"stop_reason":"end_turn"},"usage":{"output_tokens":10}}
event: message_stop
data: {"type":"message_stop"}
```
**Claude 格式错误响应**:
```json
{
"type": "error",
"error": {
"type": "authentication_error",
"message": "余额不足,请联系管理员充值"
}
}
```
### Gemini 格式端点响应(`/v1beta/models/*`)
使用 Google Gemini API 原生格式透传,错误格式:
```json
{
"error": {
"code": 400,
"message": "请求参数错误",
"status": "INVALID_ARGUMENT"
}
}
```
### 错误处理实现规范
- `WriteRelayError(w, err)` — 写入 OpenAI 格式错误,用于 `/v1/chat/completions`、`/v1/embeddings` 等 OpenAI 格式端点
- `WriteClaudeRelayError(w, err)` — 写入 Claude 格式错误,用于 `/v1/messages` 端点
- 平台级错误(余额不足、渠道不可用、频率限制)转换为供应商原生格式的错误类型,消息使用中文
- 上游供应商错误原样透传,不做二次包装
- 限流错误额外设置 `X-RateLimit-Limit`、`X-RateLimit-Remaining`、`X-RateLimit-Reset` 响应头
## 中间件配置差异
| 中间件 | 管理接口 | 代理接口 |
|--------|---------|---------|
| AdminAuth / TenantAuth(JWT) | 使用 | 不使用 |
| ApiKeyAuth(Bearer Token) | 不使用 | 使用 |
| MiddlewareHandlerResponse(统一响应) | 使用 | 不使用 |
| ErrorHandler | 使用(支付回调) | 不使用 |
| MaintenanceMode(维护模式) | 使用(租户) | 使用 |
| ContentFilter(内容过滤) | 不使用 | 使用 |
| OperationLog(操作日志) | 使用(管理后台) | 不使用 |
| OpenPlatformAuth(HMAC-SHA256) | 仅开放平台 | 不使用 |
| RBAC(权限校验) | 使用 | 不使用 |
| Idempotency(幂等性) | 按需使用 | 不使用 |
| RequestID 注入 | 使用 | 使用 |