4.3 KiB
4.3 KiB
任务 03 检查记录:接口层(路由、校验、错误处理、OpenAPI)
日期:2026-08-31
交付内容
server/src/schemas/entities.ts:全部领域实体的 Zod Schema(题目、要闻、计划、模考、会话、错题等)。server/src/schemas/api.ts:34 个接口的请求/响应 Zod Schema(路由共 31 个路径,34 个操作)。server/src/errors.ts:ApiError业务异常 + 统一错误响应格式{ error: { code, message, details } };AJV 校验信息聚合翻译为中文(如"缺少必填字段 module"、"取值不符合预设选项")。server/src/handlers/:dashboard、practice、review、plans、mock、news、questions、ai、profile 九个域的处理器。server/src/routes.ts:路由集中注册,Zod → JSON Schema(z.toJSONSchema,draft-7)转换,含 tags/summary/response。server/src/server.ts:buildServer拆分(可测试/可导出),注册@fastify/swagger+@fastify/swagger-ui,并挂载运行时端点GET /api/openapi.json(返回app.swagger())。
命令检查
pnpm --filter @gwy/server typecheck:通过。GET /api/openapi.json:200,OpenAPI 3.0.3,登记接口 31 个、文档路径 31 个,全部路由含请求/响应 Schema。- 服务启动:无 FSTWRN001 等 Schema 警告(grep 计数为 0)。
接口实测(curl)
| 接口 | 结果 |
|---|---|
GET /health |
200,{status:"ok",routes:31} |
GET /api/openapi.json |
200,约 81 KB |
GET /api/docs(Swagger UI) |
200 |
GET /api/dashboard/overview |
200,学习天数/正确率/待复习等字段齐全 |
GET /api/dashboard/trends?days=7 |
200,返回 7 天趋势数组 |
GET /api/practice/modules |
200,五大模块题量 |
POST /api/practice/start(正确参数) |
200,返回 sessionId 并持久化到 data/practice-sessions.json |
GET /api/practice/{sessionId}/question |
200,不含答案与解析 |
POST /api/practice/{sessionId}/answer |
200,{accepted:true,answeredCount:0}(记录落库留给任务08) |
POST /api/practice/{sessionId}/finish(无请求体) |
200,返回结果骨架(真实计算留给任务08) |
GET /api/questions/list?module=言语理解 |
200,分页结构正确 |
GET /api/questions/export |
200,导出 JSON |
GET /api/news/list、GET /api/news/{id} |
200 |
GET /api/review/list、GET /api/plans/today、GET /api/plans/week |
200 |
GET /api/mock-exams/analysis |
200,模块均分数组齐全 |
GET /api/profile、GET /api/settings |
200 |
POST /api/practice/start 缺字段 |
400 VALIDATION_ERROR,details 中文提示"缺少必填字段 module" |
POST /api/practice/start duration=7 |
400,聚合为一条"取值不符合预设选项" |
GET /api/questions/list?module=xingce |
400,"取值必须是允许的枚举值之一" |
| 未注册路径 | 404 NOT_FOUND,接口不存在:GET ... |
过程中发现并修复的问题
response对象中存在400: undefined键导致 Fastify 遍历报错 → 改为过滤后仅保留已定义状态码。- 无 body 的 POST 路由(如 finish)曾被占位空对象 Schema 误拒空请求体 → 无 body Schema 时直接省略
body键。 - Zod union 字面量(duration 5|10|15)在 AJV anyOf 校验下报 4 条冗余英文错误 → 错误处理器按路径聚合并翻译为单条中文提示。
practice/start未持久化会话导致后续接口 404 → 补充updateData写入会话(组卷题量、作答记录、结果计算仍为任务08 范围)。
浏览器检查
任务 03 仅涉及后端接口层,未新增前端页面。Swagger UI(http://127.0.0.1:3000/api/docs)HTTP 200 可访问,未做前端回归(前端对接在任务04+)。
当前结论
接口层完成:31 个路径全部注册并带完整 Schema;统一错误格式(400/404/500 均验证);OpenAPI 文档由运行时端点 GET /api/openapi.json 提供(不再导出静态文件);核心业务链路(start → question → answer → finish)跑通且会话已持久化。剩余 TODO 已标注在 handlers 内,归属任务08(刷题业务规则)。
微调(2026-08-31):改为「不落盘、运行时提供」——删除
server/scripts/export-openapi.ts、server/openapi.json与openapi:export脚本,前端直接消费http://localhost:3000/api/openapi.json。