主题
08 · 代码生成:一份 yaml → 前端 SDK + 后端骨架 + Mock 服务
生活类比:你是开餐厅老板,写了一份完整菜单(
openapi.yaml)。 代码生成器 = 印刷厂——一份稿子,一键给你印出:
- 前厅用的"点单 PAD 软件"(前端 SDK)
- 后厨贴的"出餐流程图"(后端 Controller 骨架)
- 临时给客人看的"试吃版"(Mock 服务)
没有印刷厂,你得手抄 50 份——这就是没有 codegen 的痛。
1. 为什么要"代码生成"
openapi.yaml
│
├─► 前端 TypeScript SDK ← 类型安全 + IDE 自动补全
├─► Java SDK / Go SDK / Swift...
├─► 后端 Spring/Express Controller 骨架
├─► Mock 服务(响应符合 schema)
├─► Postman 集合
├─► Markdown / Asciidoc 文档
└─► TypeScript 类型定义文件 (.d.ts)好处:
- ✅ 接口改字段,重新生成,前端 IDE 立刻报红
- ✅ 后端不用手写 DTO、Controller 入参签名
- ✅ 前端联调时直接
new UsersApi().listUsers(),不用拼 URL - ✅ Mock 服务让前端不必等后端
2. 三大主流代码生成器
2.1 openapi-generator(推荐,社区主流)
GitHub 60k+ star,社区维护,支持 50+ 语言/框架。
bash
# Docker 一句话(推荐)
docker run --rm -v $PWD:/local \
openapitools/openapi-generator-cli generate \
-i /local/openapi.yaml \
-g typescript-axios \
-o /local/sdk-ts
# npm 全局
npm i -g @openapitools/openapi-generator-cli
openapi-generator-cli generate -i openapi.yaml -g typescript-axios -o ./sdk-ts
# 列出所有支持的 generator
openapi-generator-cli list常用 -g 选项:
-g | 生成什么 |
|---|---|
typescript-axios | TS 客户端,axios 实现(最常用) |
typescript-fetch | TS 客户端,原生 fetch 实现 |
typescript-angular | Angular HttpClient |
typescript-rxjs | RxJS Observable 风格 |
javascript | 纯 JS |
java | Java SDK |
go | Go SDK |
python | Python SDK |
swift5 | iOS |
kotlin | Android / Kotlin Multiplatform |
spring | Spring Boot Controller 骨架 |
nodejs-express-server | Express 骨架 |
aspnetcore | ASP.NET Core |
html2 | 静态 HTML 文档 |
2.2 swagger-codegen(老牌,Swagger 官方)
跟 openapi-generator 是同源的两个分支(fork 自 swagger-codegen v2)。 openapi-generator 更新快、社区活跃,新项目无脑选它。
2.3 swagger-typescript-api(轻量级前端专用)
bash
npm i -g swagger-typescript-api
swagger-typescript-api -p ./openapi.yaml -o ./src/api -n api.ts特点:只生成一个 .ts 文件,零依赖(除了你选的 fetch/axios),适合"我不想要个 SDK 大目录"的场景。
3. 实战 · 生成前端 TypeScript SDK
3.1 准备一份 yaml
yaml
# openapi.yaml
openapi: 3.0.3
info: { title: User API, version: 1.0.0 }
servers:
- url: http://localhost:3000
paths:
/users:
get:
operationId: listUsers
tags: [user]
parameters:
- name: page
in: query
schema: { type: integer, default: 1 }
responses:
'200':
description: OK
content:
application/json:
schema:
type: array
items: { $ref: '#/components/schemas/User' }
post:
operationId: createUser
tags: [user]
requestBody:
required: true
content:
application/json:
schema: { $ref: '#/components/schemas/UserCreate' }
responses:
'201':
description: Created
content:
application/json:
schema: { $ref: '#/components/schemas/User' }
/users/{id}:
parameters:
- name: id
in: path
required: true
schema: { type: integer }
get:
operationId: getUser
tags: [user]
responses:
'200':
description: OK
content:
application/json:
schema: { $ref: '#/components/schemas/User' }
components:
schemas:
User:
type: object
properties:
id: { type: integer, readOnly: true }
name: { type: string }
email: { type: string, format: email }
required: [id, name, email]
UserCreate:
type: object
properties:
name: { type: string }
email: { type: string, format: email }
required: [name, email]3.2 生成 SDK
bash
docker run --rm -v $PWD:/local \
openapitools/openapi-generator-cli generate \
-i /local/openapi.yaml \
-g typescript-axios \
-o /local/sdk3.3 生成的目录长这样
sdk/
├── api.ts ← 主入口,所有 API 类
├── base.ts
├── common.ts
├── configuration.ts
├── index.ts
└── models/
├── user.ts ← User 类型
└── user-create.ts ← UserCreate 类型3.4 业务代码这样调
typescript
import { Configuration, UserApi, UserCreate } from './sdk';
const config = new Configuration({
basePath: 'http://localhost:3000',
accessToken: () => localStorage.getItem('token') || '',
});
const api = new UserApi(config);
// IDE 自动补全 + 类型检查!
const { data: users } = await api.listUsers(1); // 返回 User[]
const newUser: UserCreate = { name: 'Alice', email: 'alice@example.com' };
const { data: created } = await api.createUser(newUser);
console.log(created.id); // ✅ 编译期就知道有 id 字段
// console.log(created.foo); // ❌ 编译报错:Property 'foo' does not exist关键收益:接口改了字段(如把
name改成nickname),重新生成 → 所有用user.name的地方 IDE 立刻飘红——再也不会发版后才发现。
4. 实战 · 生成后端 Spring Boot 骨架
bash
docker run --rm -v $PWD:/local \
openapitools/openapi-generator-cli generate \
-i /local/openapi.yaml \
-g spring \
-o /local/server-spring \
--additional-properties=interfaceOnly=true,useSpringBoot3=true生成的 UsersApi.java(接口,不含实现):
java
public interface UsersApi {
@Operation(summary = "", operationId = "listUsers", responses = { ... })
@RequestMapping(method = RequestMethod.GET, value = "/users", produces = "application/json")
ResponseEntity<List<User>> listUsers(
@Parameter @RequestParam(value = "page", required = false, defaultValue = "1") Integer page
);
@RequestMapping(method = RequestMethod.POST, value = "/users", consumes = "application/json")
ResponseEntity<User> createUser(@Valid @RequestBody UserCreate userCreate);
@RequestMapping(method = RequestMethod.GET, value = "/users/{id}")
ResponseEntity<User> getUser(@PathVariable("id") Integer id);
}你只要写一个 @RestController implements UsersApi,专注业务逻辑——所有签名、参数校验、文档注解都已经生成好。
5. 实战 · Mock 服务(Prism)
前端不想等后端写完?用 openapi.yaml + Prism,马上起一个能返回符合 schema 的假数据的服务。
bash
docker run --rm -p 4010:4010 \
-v $PWD:/spec \
stoplight/prism:4 mock -h 0.0.0.0 /spec/openapi.yaml请求:
bash
curl http://localhost:4010/users返回(按 schema 自动生成):
json
[
{ "id": 0, "name": "string", "email": "user@example.com" }
]如果你在 yaml 里给了 example,Prism 会优先用:
yaml
schema:
$ref: '#/components/schemas/User'
example:
id: 1
name: Alice
email: alice@example.comMock 服务连接 Swagger UI 的 Try it out,前端可以完全独立调试。
6. 配置文件 · openapi-generator.yaml
不想每次命令行写一长串:
yaml
# openapi-generator.yaml
generatorName: typescript-axios
inputSpec: ./openapi.yaml
outputDir: ./sdk
additionalProperties:
npmName: '@company/api-sdk'
npmVersion: '1.0.0'
withInterfaces: true
supportsES6: true
enumPropertyNaming: originalbash
openapi-generator-cli generate -c openapi-generator.yaml6.1 常用 additionalProperties(typescript-axios)
| 选项 | 作用 |
|---|---|
npmName | 生成 package.json 的包名 |
npmVersion | 包版本 |
supportsES6 | 输出 ES6 语法 |
withInterfaces | 把 API 类拆成接口 |
withSeparateModelsAndApi | 模型 / API 分目录 |
useSingleRequestParameter | 多参数合成一个对象(更易读) |
enumPropertyNaming | enum 命名风格(original / camelCase) |
7. 整合到 CI / 项目脚本
7.1 npm scripts
json
{
"scripts": {
"gen": "openapi-generator-cli generate -i openapi.yaml -g typescript-axios -o src/api",
"gen:server": "openapi-generator-cli generate -i openapi.yaml -g spring -o ../backend/src/main/java",
"lint:api": "spectral lint openapi.yaml",
"mock": "prism mock openapi.yaml"
}
}7.2 GitHub Action / GitLab CI
yaml
# .github/workflows/api.yml
name: API codegen
on:
push:
paths: ['openapi.yaml']
jobs:
generate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Lint
run: npx @stoplight/spectral-cli lint openapi.yaml
- name: Generate TS SDK
run: |
npx @openapitools/openapi-generator-cli generate \
-i openapi.yaml -g typescript-axios -o sdk-ts
- name: Publish to npm
run: cd sdk-ts && npm publish --access public
env: { NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} }效果:后端改 yaml → push → 自动跑 lint → 自动生成新 SDK → 自动发到 npm → 前端
npm update就拿到最新类型。
8. 不只是代码:从 yaml 派生其他物料
| 工具 | 输入 | 输出 |
|---|---|---|
| openapi-generator | yaml | 50+ 语言 SDK + 后端骨架 |
| Prism | yaml | Mock 服务 |
| Postman (导入) | yaml | Postman 集合 |
| @redocly/cli build-docs | yaml | 单页 HTML 文档 |
| spectral | yaml | Lint / 质量报告 |
| schemathesis (Python) | yaml | 自动模糊测试 |
| openapi-diff | yaml1 + yaml2 | 接口变更报告(breaking 检测) |
| openapi-typescript | yaml | 纯 .d.ts 类型文件 |
9. 工程最佳实践
✅ 把 openapi.yaml 视作"源代码",跟业务代码一起 Git
✅ CI 里跑 spectral lint(确保 yaml 质量)
✅ CI 里跑 openapi-diff(检测 breaking change)
✅ 后端用 generator 出 interface,业务实现 implements 它
✅ 前端用 generator 出 SDK,私有 npm 发布或 git submodule
✅ 每次发版打 tag,让前后端版本可追溯
❌ 别把生成的代码也提交 Git(写进 .gitignore)——CI 时再生成
❌ 别手动改生成的代码——每次 generate 都被覆盖10. 章末面试题速览
- 为什么要代码生成?直接用 axios 不行吗? → 直接 axios 调用:URL 字符串拼出来 / 入参出参没类型 / 接口改字段不会报错。生成 SDK:类型安全 + IDE 补全 + 接口变更全链路 IDE 报红。
- swagger-codegen 和 openapi-generator 选哪个? → 新项目无脑 openapi-generator,社区维护、更新快、模板多。
- 接口变更怎么及时通知前端? → CI 里跑 openapi-diff 检测 breaking → 自动评论 PR;CI 自动重新生成 SDK 并发布 npm。
🎬 可视化演示
下方 demo 模拟"一份 yaml 同时生成 4 种产物"的全过程,让你直观看到 codegen 的爆发力。
→ 打开 08_codegen/demo.html
🎬 可视化演示
演示加载缓慢或样式异常?点此在新标签页打开 ↗