5.0 KiB
5.0 KiB
前端 API 开发规范(Orval 生成代码)
本规范面向 reading-platform-frontend,以 src/api/generated/ 为接口类型与路径的唯一真源,通过 Orval 从后端 OpenAPI 自动生成 TypeScript 类型 + 客户端方法。
1. 目录与职责边界
reading-platform-frontend/src/api/generated/:Orval 自动生成目录,禁止手改。api.ts:getReadingPlatformAPI()工厂函数,返回包含全部接口方法的对象。model/:OpenAPI 生成的 DTO/VO/Result/PageResult/Params 类型。
reading-platform-frontend/src/api/client.ts:项目侧的“统一入口/别名层”,导出readingApi(完整客户端实例)以及常用的类型工具(解包、分页别名等)。reading-platform-frontend/src/api/*.ts:业务侧“适配层”(可选),用于:- 兼容既有页面期望的“扁平结构/字段名/返回形态”
- 补齐 OpenAPI 暂未覆盖的历史接口(短期过渡)
- 汇聚跨接口的业务逻辑(例如组合请求、额外校验)
2. 基本原则(必须遵守)
- 生成代码只读:不得在
src/api/generated/**内做任何手工修改(包括修复类型、改路径、加字段)。 - 以生成类型为准:参数/返回类型优先使用
src/api/generated/model导出的类型,避免手写interface漂移。 - 对外只暴露稳定的业务接口:页面/组件尽量通过
src/api/*.ts(适配层)或src/api/client.ts(直接调用)访问,避免散落调用方式导致难以迁移。
3. 推荐调用方式
3.1 直接使用 Orval 客户端
- 统一从
src/api/client.ts引入:readingApi:getReadingPlatformAPI()的实例ApiResultOf/UnwrapResult/PageDataOf等类型工具
示例(以 Result<T> 为包裹结构):
import { readingApi } from "@/api/client";
import type { ResultTenant } from "@/api/generated/model";
async function loadTenant(id: number) {
const res = (await readingApi.getTenant(id)) as ResultTenant;
return res.data; // T(可能为 undefined,取决于后端返回与类型定义)
}
3.2 使用“适配层”稳定返回结构
当页面已经依赖历史返回结构(例如直接要 items/total/page/pageSize),在 src/api/*.ts 内做一次性适配,页面只消费适配后的结构。
分页适配建议统一输出:
items: T[]total: numberpage: numberpageSize: number
4. Result / PageResult 约定与解包
后端统一响应通常为:
- 普通接口:
Result<T>,字段一般为code/message/data - 分页接口:
Result<PageResult<T>>,字段一般为items/total/page/pageSize
在生成代码中常见类型形态:
ResultXXX(如ResultTenant、ResultUserInfoResponse)ResultPageResultXXX(如ResultPageResultTenant)PageResultXXX(如PageResultTenant)
建议做法:
- 组件/页面层尽量不要直接处理
ResultXXX,而是由适配层解包并做兜底(空数组、默认分页参数等)。 - 严禁在页面散落
as any;确需兼容时,集中在src/api/*.ts适配层进行,并在适配层内把“最终对页面返回的类型”定义清楚。
5. 命名与重复接口(getXxx/getXxx1/getXxx2)
由于不同角色端点(teacher/school/parent/admin)可能存在同名资源,Orval 在生成时会用 1/2/3 后缀消歧,例如:
getTask(teacher) vsgetTask1(school) vsgetTask2(parent)
规范建议:
- 业务层不要直接暴露带数字后缀的方法名;
- 在
src/api/*.ts中封装为语义化名称,例如:teacherGetTask/schoolGetTask/parentGetTask- 或按模块拆分到
src/api/teacher/task.ts等(如后续重构允许)
6. 何时需要更新生成代码
当后端 Controller 或 DTO/VO 发生变更:
- 后端更新 OpenAPI(Knife4j/SpringDoc)
- 前端更新规范并重新生成(项目已有脚本):
cd reading-platform-frontend
npm run api:update
- 提交生成物(通常包含
api-spec.*与src/api/generated/**)
注意:如果某接口在后端已存在但 OpenAPI 未导出(例如缺少注解/返回类型不规范),应优先修后端文档,而不是在前端“硬编码路径”长期绕过。
7. 禁止事项(高频踩坑)
- 禁止:手改
src/api/generated/**(下次生成会被覆盖,且会引入不可追踪差异)。 - 禁止:页面里手写 axios 调用去访问
/api/v1/...(除非 OpenAPI 暂缺且已在适配层集中兜底)。 - 禁止:在业务代码中扩散
any来“快速通过类型检查”。
8. 迁移策略(从旧 http 到 Orval)
若已有模块使用 src/api/index.ts 的 http.get/post/...:
- 短期:保留旧实现,但新增/变更接口优先走
readingApi - 中期:逐模块把旧
http调用替换为readingApi,并在适配层维持页面不改 - 长期:页面全面只依赖适配层/生成客户端,减少重复封装