news 2026/8/20 14:18:25

一套 OpenAPI,两端自动生成:Orval + 自定义 Mutator 的前端 SDK 实践

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
一套 OpenAPI,两端自动生成:Orval + 自定义 Mutator 的前端 SDK 实践

久滴直播电商平台 · 技术博客系列 第 8 篇

🔖 标签:OpenAPIOrval前端SDKTypeScript

前言

前后端协作中,最让人头疼的事情之一就是API 对接:后端改了字段名前端不知道、TypeScript 类型定义和实际响应不一致、手写的 API 调用函数重复且容易出错……

久滴直播电商平台引入了一套基于OpenAPI 3.0 + Orval的自动生成方案——从后端导出一份openapi.json,自动生成 Admin 管理后台和 UniApp 移动端两套 TypeScript API Client。本文将详细介绍这套方案的配置、使用和实践经验。

目录

  1. 手写 API 调用的痛点
  2. Orval 配置解析
  3. tags-split 模式:按 Tag 自动拆分
  4. 自定义 Mutator:Admin 用 axios,UniApp 桥接 luch-request
  5. 一键生成与 CI 校验
  6. 生成代码 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.targetOpenAPI spec 文件路径(同一份openapi.json
output.target生成文件的输出路径
output.modetags-split模式(下文详述)
output.clientHTTP 客户端类型
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:api

CI 校验

在 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 ⭐ 支持!

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/20 14:16:24

AI代理助手WorkBuddy:从零部署到核心功能验证的完整指南

这次我们来看一个名为 WorkBuddy 的 AI 代理助手项目。它不是一个简单的聊天机器人&#xff0c;而是一个旨在将复杂任务“交给 AI”去执行的智能工作伙伴。对于开发者、内容创作者或任何希望自动化工作流的人来说&#xff0c;理解并上手 WorkBuddy 意味着能解放双手&#xff0c…

作者头像 李华
网站建设 2026/8/20 14:15:46

我让AI读数据手册,它读完开始一本正经地瞎编

我让AI读数据手册&#xff0c;它读完开始一本正经地瞎编 数据手册又厚又碎&#xff0c;谁不想偷懒。我把关键章节丢给 AI&#xff0c;让它总结初始化顺序、注意坑点。它很快给了清单&#xff0c;语气笃定&#xff0c;像亲手画过芯片的人。 我对照原页&#xff0c;发现有两处是它…

作者头像 李华
网站建设 2026/8/20 14:09:31

从东风本田销量案例解析企业目标管理的科学拆解与执行协同

1. 从一份“超额完成”的销量报告说起 最近在整理行业资料时&#xff0c;翻到一份几年前的旧闻&#xff1a;东风本田在2018年的前两个月&#xff0c;累计销量达到了10.7万辆&#xff0c;超额完成了当时的阶段性目标。这看起来只是一条普通的车企销量快报&#xff0c;但如果你在…

作者头像 李华
网站建设 2026/8/20 14:07:40

Spring Boot中的JSON技术

一、前言 平日里在项目中处理JSON一般用的都是阿里巴巴的Fastjson&#xff0c;后来发现使用Spring Boot内置的Jackson来完成JSON的序列化和反序列化操作也挺方便。Jackson不但可以完成简单的序列化和反序列化操作&#xff0c;也能实现复杂的个性化的序列化和反序列化操作。 二、…

作者头像 李华
网站建设 2026/8/20 14:06:19

英飞凌全新MEMS扫描仪:如何攻克AR眼镜与车载HUD的显示难题?

1. 从一块“会动的镜子”说起&#xff1a;MEMS扫描仪的核心是什么&#xff1f; 最近在整理手头的几个项目&#xff0c;发现无论是智能眼镜还是车载HUD&#xff0c;大家讨论的焦点都开始从“能不能显示”转向了“怎么显示得更好”。这背后绕不开一个关键器件&#xff1a;MEMS扫描…

作者头像 李华
网站建设 2026/8/20 14:00:10

免费查重和免费查AI率的网站能不能用?先看它收不收录你的论文!

免费查重和免费查AI率的网站能不能用&#xff1f;先看它收不收录你的论文&#xff01; 免费的能不能用&#xff0c;先问哪个问题&#xff1f; 不是准不准&#xff0c;是你的稿子会去哪里。 免费入口的成本要有人承担。有些是大厂拿它做产品入口&#xff0c;有些是靠后续的付…

作者头像 李华