久滴直播电商平台 · 技术博客系列 第 8 篇
🔖 标签:
OpenAPIOrval前端SDKTypeScript
前言
前后端协作中,最让人头疼的事情之一就是API 对接:后端改了字段名前端不知道、TypeScript 类型定义和实际响应不一致、手写的 API 调用函数重复且容易出错……
久滴直播电商平台引入了一套基于OpenAPI 3.0 + Orval的自动生成方案——从后端导出一份openapi.json,自动生成 Admin 管理后台和 UniApp 移动端两套 TypeScript API Client。本文将详细介绍这套方案的配置、使用和实践经验。
目录
- 手写 API 调用的痛点
- Orval 配置解析
- tags-split 模式:按 Tag 自动拆分
- 自定义 Mutator:Admin 用 axios,UniApp 桥接 luch-request
- 一键生成与 CI 校验
- 生成代码 vs 手写代码的共存策略
1. 手写 API 调用的痛点
先看一个典型的手写 API 调用:
// ❌ 手写 API 调用的问题exportconstgetProductList=(params:any)=>{returnget('/product/spu/list',params)}这段代码有几个明显的问题:
params类型是any,完全丧失 TypeScript 的类型保护- 路径
/product/spu/list硬编码,后端改了路由前端不会报错 - 返回值类型未知,使用时需要手动断言
当项目有上百个 API 时,这些问题会被放大百倍。
2. Orval 配置解析
久滴平台使用 Orval 作为 OpenAPI SDK 生成工具,配置文件orval.config.ts定义了两套输出:
import{defineConfig}from'orval';exportdefaultdefineConfig({// ===== Admin 管理后台输出 =====admin:{input:{target:'./openapi.json',},output:{target:'./apps/web-antd/src/api/generated/index.ts',mode:'tags-split',client:'axios',override:{mutator:{path:'./apps/web-antd/src/api/generated/mutator.ts',name:'customInstance',},},},},// ===== UniApp 移动端输出 =====uniapp:{input:{target:'./openapi.json',},output:{target:'../jiudi-live-mall-uniapp/src/api/generated/endpoints.ts',mode:'tags-split',client:'axios',override:{mutator:{path:'../jiudi-live-mall-uniapp/src/api/generated/mutator.ts',name:'customInstance',},},},},});关键配置解读:
| 配置项 | 含义 |
|---|---|
input.target | OpenAPI spec 文件路径(同一份openapi.json) |
output.target | 生成文件的输出路径 |
output.mode | tags-split模式(下文详述) |
output.client | HTTP 客户端类型 |
override.mutator | 自定义请求拦截器 |
3. tags-split 模式:按 Tag 自动拆分
Orval 的tags-split模式会根据 OpenAPI spec 中每个接口的 Tag 自动拆分到不同文件:
src/api/generated/ ├── index.ts # 汇总导出 ├── mutator.ts # 自定义请求拦截器 ├── product.ts # Tag: Product 相关接口 ├── order.ts # Tag: Order 相关接口 ├── promotion.ts # Tag: Promotion 相关接口 ├── member.ts # Tag: Member 相关接口 ├── live.ts # Tag: Live 相关接口 └── system.ts # Tag: System 相关接口每个生成的文件包含:
- 请求函数:带完整 TypeScript 类型的 API 调用函数
- 类型定义:请求参数和响应数据的 TypeScript 接口
- JSDoc 注释:从 OpenAPI spec 中提取的接口描述
// 自动生成示例:product.ts/** * 获取商品 SPU 分页列表 * @summary 商品分页 */exportconstgetProductSpuPage=(params:ProductSpuPageReqVO)=>{returncustomInstance<PageResult<ProductSpuRespVO>>({url:'/product/spu/page',method:'GET',params,});};4. 自定义 Mutator:Admin 用 axios,UniApp 桥接 luch-request
Orval 的mutator机制允许自定义底层的 HTTP 请求实现。久滴平台利用这个特性,让两个端使用不同的 HTTP 客户端,但共享同一套 API 函数签名。
Admin 端 mutator
Admin 管理后台使用 axios,mutator 封装了 token 注入和错误处理:
// apps/web-antd/src/api/generated/mutator.tsimportaxiosfrom'axios';import{useUserStore}from'@/store';exportconstcustomInstance=async<T>(config:any):Promise<T>=>{constuserStore=useUserStore();consttoken=userStore.getToken;constinstance=axios.create({baseURL:import.meta.env.VITE_API_BASE_URL,timeout:10000,});// 注入 Authorization 头if(token){instance.defaults.headers.common['Authorization']=`Bearer${token}`;}constresponse=awaitinstance(config);// 统一响应格式解包if(response.data.code===0){returnresponse.data.data;}thrownewError(response.data.msg);};UniApp 端 mutator
UniApp 端使用luch-request(基于uni.request封装),mutator 负责桥接:
// src/api/generated/mutator.tsexportconstcustomInstance=async<T>(config:any):Promise<T>=>{consttoken=uni.getStorageSync('token');constresponse=awaituni.$uv.http.request({url:config.url,method:config.method,data:config.data||config.params,header:{Authorization:token?`Bearer${token}`:'',},});// 统一响应解包if(response.data.code===0){returnresponse.data.dataasT;}thrownewError(response.data.msg);};通过 mutator,两个端可以各自使用自己习惯的 HTTP 客户端,但 API 调用代码完全一致。
5. 一键生成与 CI 校验
久滴平台定义了两个 npm script:
{"scripts":{"gen:api":"orval --config orval.config.ts","check:api":"orval --config orval.config.ts --watch false && git diff --exit-code src/api/generated/"}}生成流程
# 1. 后端导出 openapi.json(运行中的后端 /swagger 接口)curlhttp://localhost:48080/v3/api-docs>openapi.json# 2. 一键生成两端 SDKpnpmgen:apiCI 校验
在 CI 流水线中加入check:api步骤,确保前端提交的生成代码与后端 spec 一致:
# CI 流水线步骤-name:Check API SDK consistencyrun:pnpm check:api如果开发者改了后端接口但忘了重新生成前端 SDK,CI 会自动报错拦截。
6. 生成代码 vs 手写代码的共存策略
实际项目中,不是所有 API 都适合自动生成。久滴平台的策略是:
src/api/ ├── generated/ # Orval 自动生成(不要手动修改!) │ ├── index.ts │ ├── product.ts │ └── ... ├── custom/ # 手写 API(复杂逻辑、特殊处理) │ ├── live-custom.ts │ └── upload.ts └── index.ts # 统一导出原则:
generated/目录下的文件由 Orval 管理,不要手动修改- 需要特殊处理的 API(如文件上传、WebSocket)放在
custom/目录 - 统一从
index.ts导出,业务代码不需要关心 API 来自哪个目录
总结
本文介绍了久滴直播电商平台的前端 API SDK 自动生成方案:
- Orval + OpenAPI 3.0:一份
openapi.json,自动生成 Admin + UniApp 两端 SDK - tags-split 模式:按 Tag 自动拆分 API 文件,目录结构清晰
- 自定义 mutator:Admin 用 axios,UniApp 桥接 luch-request,两端共享类型定义
- CI 校验:
pnpm check:api确保生成代码与后端接口一致,防止遗漏 - 共存策略:generated 目录自动生成,custom 目录手写特殊逻辑
下一篇我们将深入工程架构,看看 30+ Maven 模块如何组织成 Open Core 双仓架构。
📦久滴直播电商平台是一个基于 Spring Boot 3 + Vue3 + UniApp 的全栈开源直播电商解决方案。
🔗 gitee:
https://gitee.com/live-mall-pro/community(Community 版)如果觉得本文对你有帮助,欢迎 Star ⭐ 支持!