自动生成JS项目API文件
Go to file
DESKTOP-I3JPKHK\wy a2d1fb3875 添加文件下载方案 2026-04-25 19:24:12 +08:00
bin feat: initialize yx-generate-api CLI 2026-04-21 14:37:16 +08:00
src 添加文件下载方案 2026-04-25 19:24:12 +08:00
templates 更新是否生成generated/index.js 2026-04-22 11:07:26 +08:00
test 添加文件下载方案 2026-04-25 19:24:12 +08:00
.gitattributes docs: localize config template comments 2026-04-21 16:32:51 +08:00
.gitignore feat: initialize yx-generate-api CLI 2026-04-21 14:37:16 +08:00
README.md 添加文件下载方案 2026-04-25 19:24:12 +08:00
package-lock.json feat: initialize yx-generate-api CLI 2026-04-21 14:37:16 +08:00
package.json feat: improve generator reliability and usability 2026-04-21 15:39:49 +08:00

README.md

yx-generate-api

yx-generate-api 是一个面向前端项目的 Node CLI用来从 Swagger/OpenAPI JSON 生成 API 文件,并把生成目录的导出同步到你项目里的统一入口文件。

它主要解决两件事:

  • 根据接口文档自动生成 generated/*.js
  • 自动维护业务侧 index.js 里的导出区块,避免手写和漏改

先理解这 4 个命令

如果你先记住这四个命令,基本就会用了:

  • init 在当前目录生成模板配置文件和 Windows 启动脚本。
  • generate 只生成 API 文件,不改外部入口文件。
  • sync 只同步外部 index.js 的受管导出区块。
  • gen 先执行 generate,再执行 sync。日常最常用。

环境要求

  • Node ^20.19.0 || >=22.12.0
  • 业务项目里要有一个默认导出的 request 模块,生成代码会按 requestImport 指向它
  • Swagger 源可以是 http(s) 地址、file:// URL或者本地 JSON 文件路径

安装

在业务项目中直接安装:

npm install -D git+https://gitea.23544.com/wangyang/yx_generate_api_js.git

安装完成后,通常通过 npx yx-generate-api ... 调用。

快速开始

1. 生成模板文件

在业务项目根目录执行:

npx yx-generate-api init

会创建两个文件:

  • yx-generate-api.config.mjs
  • run-yx-generate-api.bat

其中 yx-generate-api.config.mjs 现在默认自带字段注释,方便首次接入时直接按提示修改。

如果文件已存在,使用 --force 覆盖:

npx yx-generate-api init --force

2. 修改配置

下面是一个和 init 模板一致的带注释示例:

export default {
  // Swagger/OpenAPI 来源。
  // 支持 http(s)、file://,也支持本地 JSON 文件路径。
  swaggerUrl: 'http://127.0.0.1:8080/swagger/v1/swagger.json',

  // 远程 Swagger 加载超时时间,单位毫秒。
  swaggerTimeoutMs: 20000,

  // 生成文件输出目录。
  // 相对路径会基于当前配置文件所在目录解析。
  outputDir: 'src/api/aixue/generated',

  // 是否生成 outputDir/index.js。
  // 关闭后只保留 shared.js 和各模块文件sync / gen 也会默认不再同步。
  generateIndexFile: true,

  // 由 `sync` / `gen` 维护的外部 API 入口文件。
  externalIndexFile: 'src/api/aixue/index.js',

  // 写入到生成模块中的 request 导入路径。
  // 这个路径必须相对于每个生成后的模块文件来写。
  requestImport: '../request',

  // 生成函数的参数风格,可选 'object' 或 'positional'。
  paramStyle: 'object',

  // 全量生成时,是否清理已经过期的自动生成模块文件。
  // 如果是部分模块生成,会自动跳过清理,避免误删其他模块。
  cleanOutput: true,

  sync: {
    // 如果你只想生成文件、不想改 externalIndexFile可以设为 false。
    // 当 generateIndexFile=false 时,这个开关默认也会变成 false。
    enabled: true,

    // 是否在受管区块中附带 generated/index.js 的注释快照。
    includeGeneratedIndexSnapshot: true,

    // externalIndexFile 里受管区块的开始和结束标记。
    blockStart: '// AUTO-GENERATED API EXPORTS START',
    blockEnd: '// AUTO-GENERATED API EXPORTS END',

    // 可选:
    // snapshotTitle: '// generated/index.js content:',
    // exportFrom: './generated',
  },
}

3. 执行生成

npx yx-generate-api gen

这条命令会:

  1. 拉取 swaggerUrl
  2. outputDir 下生成 API 文件
  3. 如果 generateIndexFile=true,生成 outputDir/index.js
  4. 如果 sync.enabled=true,把导出同步到 externalIndexFile

一个完整的日常流程

第一次接入时:

npx yx-generate-api init
npx yx-generate-api gen

后端接口更新后,通常只需要再执行一次:

npx yx-generate-api gen

如果你只是想重新整理外部入口文件,而不重新拉 Swagger

npx yx-generate-api sync

配置说明

所有写在配置文件里的路径,默认都相对于配置文件所在目录,而不是命令执行目录。

顶层配置

  • swaggerUrl Swagger/OpenAPI JSON 来源。支持 http(s)file://、本地 JSON 文件路径。生成时必填。
  • swaggerTimeoutMs 拉取远程 Swagger 的超时时间,单位毫秒,默认 20000
  • outputDir 生成目录。默认是 src/api/generated
  • externalIndexFile 业务侧统一导出文件,例如 src/api/index.js。如果不填,默认不会执行同步。
  • generateIndexFile 是否生成 outputDir/index.js。默认 true。设为 false 后,工具只生成 shared.js 和各模块文件;sync.enabled 的默认值也会随之变成 false
  • requestImport 生成模块里 import request from '...' 的路径。它应该相对于每个生成出来的模块文件。
  • paramStyle 函数参数风格,可选 objectpositional,默认 object
  • cleanOutput 是否在“全量生成”时清理当前输出目录里已经过期的自动生成模块文件。默认 true
  • sync 控制 sync / gen 如何维护外部入口文件。

sync 配置

  • sync.enabled 是否启用同步。默认值等于 Boolean(externalIndexFile && generateIndexFile)
  • sync.blockStart 受管区块开始标记。
  • sync.blockEnd 受管区块结束标记。
  • sync.includeGeneratedIndexSnapshot 是否把 generated/index.js 的内容以注释形式写进受管区块。默认 true
  • sync.snapshotTitle 快照标题。默认是 // generated/index.js content:
  • sync.exportFrom 自定义 export * from '...' 的路径。不填时会自动根据 externalIndexFileoutputDir 计算。

命令详解

init

用途:在当前目录创建模板配置文件和 Windows 启动脚本。

npx yx-generate-api init
npx yx-generate-api init --force

generate

用途:只生成 API 文件,不同步外部入口。

npx yx-generate-api generate

常用写法:

npx yx-generate-api generate Curriculum
npx yx-generate-api generate class-assignment Ranking
npx yx-generate-api generate --modules=Curriculum,class-assignment
npx yx-generate-api generate --config ./yx-generate-api.config.mjs
npx yx-generate-api generate --url=http://127.0.0.1:8080/swagger/v1/swagger.json
npx yx-generate-api generate --url ./swagger/swagger.json
npx yx-generate-api generate --outDir=src/api/tmp-generated
npx yx-generate-api generate --requestImport=../request
npx yx-generate-api generate --timeout 10000
npx yx-generate-api generate --no-clean
npx yx-generate-api generate --paramStyle=positional

支持的参数:

  • --config=... 指定配置文件路径。
  • --url=... 临时覆盖 swaggerUrl
  • --timeout=... 临时覆盖 Swagger 拉取超时,单位毫秒。
  • --outDir=... 临时覆盖输出目录。
  • --requestImport=... 临时覆盖生成文件里的 request 导入路径。
  • --modules=... 逗号分隔的模块列表。
  • --clean 全量生成时清理过期的自动生成模块文件。
  • --no-clean 保留已有生成模块文件。
  • --paramStyle=object|positional 临时覆盖参数风格。

命令行参数既支持 --key=value,也支持 --key value

sync

用途:只同步外部入口文件。

npx yx-generate-api sync
npx yx-generate-api sync --config=./yx-generate-api.config.mjs

如果 sync.enabled=false,命令会直接跳过。

gen

用途:先 generate,再 sync。这是推荐的日常命令。

npx yx-generate-api gen
npx yx-generate-api gen Curriculum
npx yx-generate-api gen --modules=Curriculum,class-assignment

gen 接受和 generate 相同的运行时参数,例如 --config--url--timeout--outDir--requestImport--paramStyle--modules--clean

模块筛选规则

如果不传模块名,会生成 Swagger 里的全部模块。

如果传了模块名,只会生成匹配到的模块,例如:

npx yx-generate-api generate Curriculum
npx yx-generate-api generate class-assignment Ranking
npx yx-generate-api generate --modules=Curriculum,class-assignment

模块匹配时会同时参考这些值:

  • 推导出的模块名
  • 模块文件名的 kebab-case 形式
  • Swagger operation 的 tags

匹配时会忽略大小写和大部分分隔符,所以下面这些通常都能匹配到同一个模块:

  • Curriculum
  • curriculum
  • class-assignment
  • classAssignment

模块名是怎么推导的

生成器会优先从接口路径推导模块名:

  • /api/v1/Curriculum/list -> Curriculum
  • /api/Curriculum/list -> Curriculum
  • 其他路径会优先使用第一个路径段
  • 如果路径不合适,会退回到 Swagger tags[0]

生成结果长什么样

假设配置如下:

export default {
  outputDir: 'src/api/aixue/generated',
  externalIndexFile: 'src/api/aixue/index.js',
  requestImport: '../request',
}

执行 npx yx-generate-api gen 后,通常会得到这样的结构:

src/api/aixue/
  index.js
  request.js
  generated/
    shared.js
    curriculum.js
    class-assignment.js
    index.js

其中:

  • shared.js 提供 buildUrlstringifyParams 等公共方法,不再依赖额外的 qs 包。
  • curriculum.js 某个模块的 API 方法集合。
  • generated/index.js 汇总导出每个模块,同时提供“命名空间导出”和“扁平函数导出”。
  • src/api/aixue/index.js 业务侧入口文件,sync 会在里面维护一个受管区块。

generated/index.js 的内容类似这样:

export * as classAssignmentApi from './class-assignment'
export * as curriculumApi from './curriculum'

export * from './class-assignment'
export * from './curriculum'

这样你可以同时支持两种写法:

import { curriculumApi } from '@/api/aixue/generated'
import { getCurriculumListApi } from '@/api/aixue/generated'

如果你不需要这个聚合入口,也可以这样关闭:

generateIndexFile: false

关闭后会有这些变化:

  • 不再生成 generated/index.js
  • 旧的自动生成 generated/index.js 会在下次生成时被移除
  • 不再对“跨模块扁平导出重名”做 generated/index.js 级别的冲突校验
  • sync.enabled 默认会变成 false

如果你又显式把 sync.enabled 设成 true,命令会直接报错,因为 sync 依赖 generated/index.js

需要注意:

  • 如果不同模块里恰好生成了同名函数,例如都生成了 getListApi
  • 那么 generated/index.js 里的 export * from './module' 会产生冲突
  • 如果某个接口的默认函数名刚好会和模块命名空间导出名撞上,例如 /api/Values 同时会推导出模块命名空间 valuesApi
  • 工具会在生成阶段自动把函数名调整成不冲突的形式,例如 getValuesApi
  • 工具会先列出冲突函数、对应模块名,以及能识别到的完整接口 URL
  • 在交互终端里会给你两个选择:
  • 1 在函数名后自动追加模块名,例如 getListEnglishWordApi
  • 2 退出本次生成
  • 如果自动重命名后仍然冲突,工具会直接失败,并提示“依然冲突无法执行”

参数风格

paramStyle 决定生成函数的签名长什么样。

object

默认值。路径参数和查询参数统一放到 params,请求体放到 data

const detailApi = (params = {}) => request.get(buildUrl(`/api/v1/course/{id}`, params))

const createApi = (params = {}, data) => request.post(buildUrl(`/api/v1/course/{id}`, params), data)

适合大多数前端项目,调用时更稳定,也更适合参数经常变动的接口。

positional

路径参数和查询参数会展开成位置参数,请求体仍然放最后一个 data

const detailApi = (id, tab) => request.get(buildUrl(`/api/v1/course/{id}`, { id, tab }))

const createApi = (id, data) => request.post(buildUrl(`/api/v1/course/{id}`, { id }), data)

适合你明确想要“函数参数看起来更直接”的场景。

文件下载接口

如果响应声明为 type: string, format: binary、Swagger 2 的 type: file,或者使用常见文件下载 MIME 类型,例如 application/octet-streamapplication/pdf、Excel、CSV、图片、音视频等生成代码会自动带上 responseType: 'blob'

有些后端 Swagger 不会给导出接口声明响应 content / schema。这种情况下,如果接口路径、operationId、摘要或描述里能识别到 导出下载exportdownload,或者 GET 接口名里有独立的 File 单词,也会按文件下载处理。若响应已经明确声明为 JSON 或普通 schema则不会走这个兜底推断。

const exportApi = (params = {}) =>
  request.get(buildUrl(`/api/v1/report/export`, params), { responseType: 'blob' })

const createExportApi = (data) =>
  request.post(`/api/v1/report/export`, data, { responseType: 'blob' })

sync 会怎么改外部入口文件

sync 不会粗暴覆盖整个 externalIndexFile,它只维护一段带开始和结束标记的受管区块。

默认写进去的内容类似这样:

// AUTO-GENERATED API EXPORTS START
// Synced from 'src/api/aixue/generated/index.js'. Do not edit manually.
// generated/index.js content:
// export * as curriculumApi from './curriculum'
// export * as rankingApi from './ranking'
// export * from './curriculum'
// export * from './ranking'
export * from './generated'
// AUTO-GENERATED API EXPORTS END

规则是:

  • 如果外部文件里已经有这段标记,sync 会替换这段区块
  • 如果还没有,sync 会把区块追加到文件末尾
  • 标记外的内容会保留

如果你不想把 generated/index.js 的快照写进注释,可以把:

sync: {
  includeGeneratedIndexSnapshot: false,
}

Windows 双击运行

init 会同时创建 run-yx-generate-api.bat

它支持两种使用方式:

  • 直接双击运行 会先提示你输入模块名或额外参数;留空则执行全量生成。
  • 在命令行里带参数运行 会直接把参数透传给 yx-generate-api gen

它内部的核心行为相当于:

npx yx-generate-api gen %*

双击时可输入的内容示例:

Curriculum
Ranking EnglishWord
--modules=Ranking,EnglishWord

适合给不常开命令行的同事直接双击执行,也保留了命令行传参的灵活性。

也可以在命令行里继续传参:

run-yx-generate-api.bat Curriculum
run-yx-generate-api.bat --modules=Curriculum,class-assignment

无论你是直接执行 npx yx-generate-api gen,还是走 .bat,后续真正执行的都是同一套 CLI。

所以如果遇到 API 函数名冲突,两边都会出现同样的冲突提示和同样的两个处理选项。

常见问题

1. 为什么 gen 没有同步外部 index.js

通常是下面几种情况:

  • 没有配置 externalIndexFile
  • sync.enabled=false
  • 你执行的是 generate,不是 gen

2. 为什么生成文件里的 request 路径不对

requestImport 会原样写进生成文件,所以它必须相对于生成后的模块文件来写,而不是相对于 externalIndexFile

例如生成目录是 src/api/aixue/generated,请求封装在 src/api/aixue/request.js,那么应该写:

requestImport: '../request'

3. 为什么命令行传的 --outDir 看起来和配置文件规则不一样

配置文件里的路径相对于“配置文件所在目录”。

命令行传入的 --config--outDir,相对于“当前执行命令的目录”。

4. 为什么提示模块找不到

说明你传入的模块名没有匹配到任何已解析模块。可以先不带模块参数跑一次全量生成,观察生成出来的模块文件名,再按那个名字筛选。

5. 为什么有些旧模块文件没有被删掉

只有“全量生成”时,cleanOutput=true 才会清理过期的自动生成模块文件。

如果你这次是只生成部分模块,例如:

npx yx-generate-api generate Curriculum

工具会保留其他已有模块,避免误删。

6. 为什么生成时报“Duplicate API export names detected”

说明不同模块之间出现了重复的扁平函数导出名。

常见场景有两种:

  • 两个或多个模块里生成了同名函数,例如都导出了 getListApi
  • 你只生成了部分模块,但保留目录里已有模块,导致新旧模块之间出现了同名导出

因为 generated/index.js 会使用:

export * from './module-a'
export * from './module-b'

这种模式下,重复的扁平导出名不能直接共存。

/api/Values 这类“函数默认名刚好和模块命名空间名相同”的情况,工具会在生成阶段自动规避,不会再单独报这个冲突。

如果你是从旧版本升级过来,而 generated 目录里还保留着旧规则生成的模块文件,也可能在部分生成时触发这类校验。遇到这种情况,直接做一次全量生成,或者把冲突模块一起重新生成即可。

所以工具会先把冲突明细列出来,内容会尽量包含:

  • 冲突函数名
  • 对应模块名
  • 对应的完整接口 URL

然后给你两个选择:

  • 1 自动把冲突函数改成“原函数名 + 模块名”,例如 getListApi -> getListEnglishWordApi
  • 2 退出生成,不写入本次结果

如果你选了自动重命名,但重命名后依然冲突,例如模块内已经存在同名函数,那么工具会直接失败并提示当前结果仍然无法安全生成。

本地开发

在工具仓库里直接查看帮助:

node ./bin/yx-generate-api.js --help
node ./bin/yx-generate-api.js generate --help
node ./bin/yx-generate-api.js sync --help