yx_generate_api_js/README.md

472 lines
13 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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`。它会先切到脚本所在目录,再执行:
```bat
npx yx-generate-api gen %*
```
适合给不常开命令行的同事直接双击执行。
也可以在命令行里继续传参:
```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
```