架构
API 契约
统一响应信封、分页约定、错误码规范与完整端点总览。
五个应用共用同一份 API 契约。契约真源是 apps/nest/openapi/openapi.yaml —— 先定义 Contract,再动手实现;不允许为了写起来顺手就自行改动契约。
统一响应信封
成功响应只包一层 data,不额外塞 code / msg / success —— HTTP 状态码已经表达了结果状态。
// 单个资源
{ "data": { "id": "V1StGXR8_Z5j", "username": "admin" } }// 列表:data + pagination
{
"data": [],
"pagination": { "page": 1, "pageSize": 20, "total": 100 }
}失败响应用大写蛇形错误码:
{ "code": "USER_NOT_FOUND", "message": "用户不存在" }为什么成功不返回 code
只有一种成功,却有很多种失败。把 code 留给失败路径,前端判错只需要看 response.ok,少一层无意义的判断。
路径与命名约定
| 约定 | 规则 |
|---|---|
| 前缀 | 统一 /api |
| 风格 | RESTful,资源用复数名词(/users、/roles、/notices) |
| 字段名 | 统一 camelCase |
| 时间格式 | 统一 ISO 8601 |
| 认证头 | Authorization: Bearer <accessToken> |
分页约定
列表接口的查询参数是固定的几个:
| 参数 | 默认值 | 说明 |
|---|---|---|
page | 1 | 页码 |
pageSize | 10 | 每页条数,枚举值 10 / 20 / 30 / 40 / 50 |
search | — | 关键词搜索 |
sort | — | 排序字段 |
order | — | asc / desc |
权限声明
契约里用 x-permission 扩展标注每个端点所需的权限位。这既是给文档读的,也是服务端守卫的依据来源。
/users:
get:
summary: 用户列表
x-permission: SEARCH拿不到所需权限位时返回 403:
{ "code": "FORBIDDEN", "message": "无权限" }未携带或携带无效 Token 时返回 401(code 为 UNAUTHORIZED)。
端点总览
当前契约共 48 条路径 / 77 个操作(真源 openapi.yaml,v1.14.0),按模块分:
| 方法 | 路径 | 说明 |
|---|---|---|
POST | /auth/login | 登录,返回双 Token 与用户信息 |
POST | /auth/refresh | 刷新 accessToken(refreshToken 会轮换,旧 token 作废) |
POST | /auth/logout | 登出,撤销托管的 refreshToken,返回 204 |
GET | /auth/me | 当前用户信息与聚合权限位 |
POST | /auth/demo-login | 演示环境快捷登录(DEMO_MODE=true 才存在,否则 404;kind 取 admin / random) |
GET PUT | /account/profile | 个人资料 |
PUT | /account/email | 修改邮箱 |
PUT | /account/password | 修改密码(触发全端下线) |
POST | /account/avatar | 上传头像 |
改契约的流程
因为五端共用一份契约,改动的代价必须被看见:
- 先改
openapi/openapi.yaml—— 它是唯一真源; - 逐端评估影响面:React、Vue、Next.js、Nuxt、NestJS 五端都要过一遍;
- 再落到各端实现;
- 错误码统一登记,禁止散落到各端。
交互式文档由 Scalar 渲染(原先的 Swagger UI 已替换),原始 JSON 仍保留在 /docs-json 供工具消费。