kindergarten_java/docs/前端API开发规范-Orval.md
2026-03-11 14:38:43 +08:00

5.0 KiB
Raw Blame History

前端 API 开发规范Orval 生成代码)

本规范面向 reading-platform-frontend,以 src/api/generated/接口类型与路径的唯一真源,通过 Orval 从后端 OpenAPI 自动生成 TypeScript 类型 + 客户端方法。

1. 目录与职责边界

  • reading-platform-frontend/src/api/generated/Orval 自动生成目录,禁止手改
    • api.tsgetReadingPlatformAPI() 工厂函数,返回包含全部接口方法的对象。
    • 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: number
  • page: number
  • pageSize: number

4. Result / PageResult 约定与解包

后端统一响应通常为:

  • 普通接口Result<T>,字段一般为 code/message/data
  • 分页接口Result<PageResult<T>>,字段一般为 items/total/page/pageSize

在生成代码中常见类型形态:

  • ResultXXX(如 ResultTenantResultUserInfoResponse
  • ResultPageResultXXX(如 ResultPageResultTenant
  • PageResultXXX(如 PageResultTenant

建议做法:

  • 组件/页面层尽量不要直接处理 ResultXXX,而是由适配层解包并做兜底(空数组、默认分页参数等)。
  • 严禁在页面散落 as any;确需兼容时,集中在 src/api/*.ts 适配层进行,并在适配层内把“最终对页面返回的类型”定义清楚。

5. 命名与重复接口(getXxx/getXxx1/getXxx2

由于不同角色端点teacher/school/parent/admin可能存在同名资源Orval 在生成时会用 1/2/3 后缀消歧,例如:

  • getTaskteacher vs getTask1school vs getTask2parent

规范建议:

  • 业务层不要直接暴露带数字后缀的方法名
  • src/api/*.ts 中封装为语义化名称,例如:
    • teacherGetTask / schoolGetTask / parentGetTask
    • 或按模块拆分到 src/api/teacher/task.ts 等(如后续重构允许)

6. 何时需要更新生成代码

当后端 Controller 或 DTO/VO 发生变更:

  1. 后端更新 OpenAPIKnife4j/SpringDoc
  2. 前端更新规范并重新生成(项目已有脚本):
cd reading-platform-frontend
npm run api:update
  1. 提交生成物(通常包含 api-spec.*src/api/generated/**

注意:如果某接口在后端已存在但 OpenAPI 未导出(例如缺少注解/返回类型不规范),应优先修后端文档,而不是在前端“硬编码路径”长期绕过。

7. 禁止事项(高频踩坑)

  • 禁止:手改 src/api/generated/**(下次生成会被覆盖,且会引入不可追踪差异)。
  • 禁止:页面里手写 axios 调用去访问 /api/v1/...(除非 OpenAPI 暂缺且已在适配层集中兜底)。
  • 禁止:在业务代码中扩散 any 来“快速通过类型检查”。

8. 迁移策略(从旧 http 到 Orval

若已有模块使用 src/api/index.tshttp.get/post/...

  • 短期:保留旧实现,但新增/变更接口优先走 readingApi
  • 中期:逐模块把旧 http 调用替换为 readingApi,并在适配层维持页面不改
  • 长期:页面全面只依赖适配层/生成客户端,减少重复封装