# 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 文件路径 ## 安装 在业务项目中直接安装: ```bash npm install -D git+https://gitea.23544.com/wangyang/yx_generate_api_js.git ``` 安装完成后,通常通过 `npx yx-generate-api ...` 调用。 ## 快速开始 ### 1. 生成模板文件 在业务项目根目录执行: ```bash npx yx-generate-api init ``` 会创建两个文件: - `yx-generate-api.config.mjs` - `run-yx-generate-api.bat` 其中 `yx-generate-api.config.mjs` 现在默认自带字段注释,方便首次接入时直接按提示修改。 如果文件已存在,使用 `--force` 覆盖: ```bash npx yx-generate-api init --force ``` ### 2. 修改配置 下面是一个和 `init` 模板一致的带注释示例: ```js 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', // 由 `sync` / `gen` 维护的外部 API 入口文件。 externalIndexFile: 'src/api/aixue/index.js', // 写入到生成模块中的 request 导入路径。 // 这个路径必须相对于每个生成后的模块文件来写。 requestImport: '../request', // 生成函数的参数风格,可选 'object' 或 'positional'。 paramStyle: 'object', // 全量生成时,是否清理已经过期的自动生成模块文件。 // 如果是部分模块生成,会自动跳过清理,避免误删其他模块。 cleanOutput: true, sync: { // 如果你只想生成文件、不想改 externalIndexFile,可以设为 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. 执行生成 ```bash npx yx-generate-api gen ``` 这条命令会: 1. 拉取 `swaggerUrl` 2. 在 `outputDir` 下生成 API 文件 3. 生成 `outputDir/index.js` 4. 把导出同步到 `externalIndexFile` ## 一个完整的日常流程 第一次接入时: ```bash npx yx-generate-api init npx yx-generate-api gen ``` 后端接口更新后,通常只需要再执行一次: ```bash npx yx-generate-api gen ``` 如果你只是想重新整理外部入口文件,而不重新拉 Swagger: ```bash 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`。如果不填,默认不会执行同步。 - `requestImport` 生成模块里 `import request from '...'` 的路径。它应该相对于每个生成出来的模块文件。 - `paramStyle` 函数参数风格,可选 `object` 或 `positional`,默认 `object`。 - `cleanOutput` 是否在“全量生成”时清理当前输出目录里已经过期的自动生成模块文件。默认 `true`。 - `sync` 控制 `sync` / `gen` 如何维护外部入口文件。 ### sync 配置 - `sync.enabled` 是否启用同步。默认值等于 `Boolean(externalIndexFile)`。 - `sync.blockStart` 受管区块开始标记。 - `sync.blockEnd` 受管区块结束标记。 - `sync.includeGeneratedIndexSnapshot` 是否把 `generated/index.js` 的内容以注释形式写进受管区块。默认 `true`。 - `sync.snapshotTitle` 快照标题。默认是 `// generated/index.js content:`。 - `sync.exportFrom` 自定义 `export * from '...'` 的路径。不填时会自动根据 `externalIndexFile` 和 `outputDir` 计算。 ## 命令详解 ### `init` 用途:在当前目录创建模板配置文件和 Windows 启动脚本。 ```bash npx yx-generate-api init npx yx-generate-api init --force ``` ### `generate` 用途:只生成 API 文件,不同步外部入口。 ```bash npx yx-generate-api generate ``` 常用写法: ```bash 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` 用途:只同步外部入口文件。 ```bash npx yx-generate-api sync npx yx-generate-api sync --config=./yx-generate-api.config.mjs ``` 如果 `sync.enabled=false`,命令会直接跳过。 ### `gen` 用途:先 `generate`,再 `sync`。这是推荐的日常命令。 ```bash 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 里的全部模块。 如果传了模块名,只会生成匹配到的模块,例如: ```bash 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]` ## 生成结果长什么样 假设配置如下: ```js export default { outputDir: 'src/api/aixue/generated', externalIndexFile: 'src/api/aixue/index.js', requestImport: '../request', } ``` 执行 `npx yx-generate-api gen` 后,通常会得到这样的结构: ```text src/api/aixue/ index.js request.js generated/ shared.js curriculum.js class-assignment.js index.js ``` 其中: - `shared.js` 提供 `buildUrl`、`stringifyParams` 等公共方法,不再依赖额外的 `qs` 包。 - `curriculum.js` 某个模块的 API 方法集合。 - `generated/index.js` 汇总导出每个模块,同时提供“命名空间导出”和“直接函数导出”。 - `src/api/aixue/index.js` 业务侧入口文件,`sync` 会在里面维护一个受管区块。 `generated/index.js` 的内容类似这样: ```js export * as classAssignmentApi from './class-assignment' export * as curriculumApi from './curriculum' export { getClassAssignmentListApi } from './class-assignment' export { getCurriculumListApi } from './curriculum' ``` 如果不同模块里恰好生成了同名函数,`generated/index.js` 会自动为冲突项补上模块前缀别名,避免导出冲突。 ## 参数风格 `paramStyle` 决定生成函数的签名长什么样。 ### `object` 默认值。路径参数和查询参数统一放到 `params`,请求体放到 `data`。 ```js 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`。 ```js 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) ``` 适合你明确想要“函数参数看起来更直接”的场景。 ## `sync` 会怎么改外部入口文件 `sync` 不会粗暴覆盖整个 `externalIndexFile`,它只维护一段带开始和结束标记的受管区块。 默认写进去的内容类似这样: ```js // 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 './generated' // AUTO-GENERATED API EXPORTS END ``` 规则是: - 如果外部文件里已经有这段标记,`sync` 会替换这段区块 - 如果还没有,`sync` 会把区块追加到文件末尾 - 标记外的内容会保留 如果你不想把 `generated/index.js` 的快照写进注释,可以把: ```js sync: { includeGeneratedIndexSnapshot: false, } ``` ## Windows 双击运行 `init` 会同时创建 `run-yx-generate-api.bat`。 它支持两种使用方式: - 直接双击运行 会先提示你输入模块名或额外参数;留空则执行全量生成。 - 在命令行里带参数运行 会直接把参数透传给 `yx-generate-api gen`。 它内部的核心行为相当于: ```bat npx yx-generate-api gen %* ``` 双击时可输入的内容示例: ```bat Curriculum Ranking EnglishWord --modules=Ranking,EnglishWord ``` 适合给不常开命令行的同事直接双击执行,也保留了命令行传参的灵活性。 也可以在命令行里继续传参: ```bat run-yx-generate-api.bat Curriculum run-yx-generate-api.bat --modules=Curriculum,class-assignment ``` ## 常见问题 ### 1. 为什么 `gen` 没有同步外部 `index.js` 通常是下面几种情况: - 没有配置 `externalIndexFile` - `sync.enabled=false` - 你执行的是 `generate`,不是 `gen` ### 2. 为什么生成文件里的 `request` 路径不对 `requestImport` 会原样写进生成文件,所以它必须相对于生成后的模块文件来写,而不是相对于 `externalIndexFile`。 例如生成目录是 `src/api/aixue/generated`,请求封装在 `src/api/aixue/request.js`,那么应该写: ```js requestImport: '../request' ``` ### 3. 为什么命令行传的 `--outDir` 看起来和配置文件规则不一样 配置文件里的路径相对于“配置文件所在目录”。 命令行传入的 `--config`、`--outDir`,相对于“当前执行命令的目录”。 ### 4. 为什么提示模块找不到 说明你传入的模块名没有匹配到任何已解析模块。可以先不带模块参数跑一次全量生成,观察生成出来的模块文件名,再按那个名字筛选。 ### 5. 为什么有些旧模块文件没有被删掉 只有“全量生成”时,`cleanOutput=true` 才会清理过期的自动生成模块文件。 如果你这次是只生成部分模块,例如: ```bash npx yx-generate-api generate Curriculum ``` 工具会保留其他已有模块,避免误删。 ## 本地开发 在工具仓库里直接查看帮助: ```bash node ./bin/yx-generate-api.js --help node ./bin/yx-generate-api.js generate --help node ./bin/yx-generate-api.js sync --help ```