UNPKG

@shixinde/apifox-swagger

Version:

从 Apifox 导出 Swagger/OpenAPI 文档并生成 TypeScript 类型定义的工具

549 lines (411 loc) 13.4 kB
# @shixinde/apifox-swagger 一个用于从 Apifox 导出 Swagger/OpenAPI 文档并生成 TypeScript 类型定义的工具。 ## 功能特性 - 🚀 支持从 Apifox 云端 API 导出文档 - 🏠 支持从本地 Apifox 客户端导出文档 - 📝 自动生成 TypeScript 类型定义 - 🔧 支持命令行工具和编程接口 - ⚙️ 支持配置文件 - 🛠️ 自动处理 OpenAPI 格式兼容性 ## 安装 ```bash npm install @shixinde/apifox-swagger # 或 yarn add @shixinde/apifox-swagger # 或 pnpm add @shixinde/apifox-swagger ``` ## 使用方法 ### 1. 命令行工具 安装后可以直接使用 `apifox-swagger` 命令: #### 云端模式(推荐) ```bash # 基本用法 - 导出整个项目 apifox-swagger apifox-swagger --projectId 2364643 --outdir ./output # 导出指定文件夹 apifox-swagger apifox-swagger --projectId 2364643 --folderId 123456 --folderName "用户模块" --outdir ./output # 使用 token 参数 apifox-swagger apifox-swagger --projectId 2364643 --outdir ./output --token your-access-token # 或使用环境变量 APIFOX_ACCESS_TOKEN=your-token apifox-swagger apifox-swagger --projectId 2364643 --outdir ./output ``` <!-- #### 本地模式() ```bash # 从本地 Apifox 客户端导出(需要 Apifox 客户端运行) apifox-swagger apifox-swagger --local --outdir ./output # 诊断本地客户端状态 ./diagnose-local.sh ``` --> #### 命令行选项 - `--projectId <projectId>`: Apifox 项目 ID(云端导出时必需) - `--outdir <outdir>`: 输出目录(默认:`./apifox`- `--token <token>`: 访问令牌(可替代环境变量) - `--local`: 从本地 Apifox 客户端导出 - `--folderId <folderId>`: 指定文件夹 ID - `--folderName <folderName>`: 指定文件夹名称 ### 2. 编程接口 #### 基本用法 ```javascript import { exportSwagger } from '@shixinde/apifox-swagger'; // 从云端导出 const result = await exportSwagger({ projectId: '2364643', token: 'your-access-token', outdir: './output', useLocal: false }); // 从本地客户端导出 const result = await exportSwagger({ outdir: './output', useLocal: true }); ``` #### 使用配置文件 创建 `apifox.config.js````javascript export default { projectId: '2364643', outdir: './src/types', useLocal: false, // token: 'your-token', // 可选,也可通过环境变量设置 }; ``` 创建导出脚本 `scripts/export-api.js````javascript import { exportSwagger } from '@shixinde/apifox-swagger'; import config from '../apifox.config.js'; async function runExport() { try { const result = await exportSwagger({ ...config, token: config.token || process.env.APIFOX_ACCESS_TOKEN }); console.log('导出成功:', result); } catch (error) { console.error('导出失败:', error.message); } } runExport(); ````package.json` 中添加脚本: ```json { "scripts": { "export-api": "node scripts/export-api.js" } } ``` ### 3. 环境变量 可以通过环境变量设置访问令牌: ```bash export APIFOX_ACCESS_TOKEN=your-access-token ``` 或在 `.env` 文件中: ``` APIFOX_ACCESS_TOKEN=your-access-token APIFOX_PROJECT_ID=2364643 ``` ## 输出文件 工具会在指定的输出目录下创建 `swagger` 文件夹,包含: - `all.json`: OpenAPI/Swagger JSON 文档 - `all.ts`: TypeScript 类型定义文件 如果指定了文件夹名称,文件名会使用文件夹名称替代 `all`## API 参考 ### exportSwagger(options) 导出 Swagger 文档的主要函数。 #### 参数 - `options.projectId` (string): Apifox 项目 ID(云端导出时必需) - `options.token` (string): 访问令牌(可选,优先级高于环境变量) - `options.outdir` (string): 输出目录 - `options.useLocal` (boolean): 是否使用本地客户端(默认:false) - `options.folderId` (string): 文件夹 ID(可选) - `options.folderName` (string): 文件夹名称(可选) #### 返回值 返回一个 Promise,解析为包含导出信息的对象。 ## 获取 Apifox 访问令牌 1. 登录 [Apifox 网页版](https://www.apifox.cn/) 2. 进入个人设置 → API 访问令牌 3. 创建新的访问令牌 4. 复制令牌并妥善保存 ## 获取项目 ID 1. 在 Apifox 中打开你的项目 2. 查看浏览器地址栏,URL 中包含项目 ID 3. 例如:`https://www.apifox.cn/web/project/2364643` 中的 `2364643` 就是项目 ID ## 故障排除 <!-- ### 本地模式问题 如果本地模式导出失败,请按以下步骤排查: 1. **运行诊断脚本**```bash ./diagnose-local.sh ``` 2. **确保 Apifox 客户端正确配置** - Apifox 客户端正在运行 - 已打开至少一个项目 - 项目中有 API 接口定义 - 本地 API 服务已启用(端口 4523-4527) 3. **查看详细文档**```bash cat LOCAL_USAGE.md ``` 4. **常见解决方案** - 重启 Apifox 应用程序 - 确保项目中至少有一个 API 接口 - 检查防火墙是否阻止本地连接 --> ### 云端模式问题 1. **检查访问令牌** - 确保 `APIFOX_ACCESS_TOKEN` 环境变量已设置 - 或使用 `--token` 参数传递令牌 2. **检查项目信息** - 验证项目 ID 是否正确 - 确保有项目访问权限 3. **网络连接** - 验证网络连接是否正常 - 检查是否有代理或防火墙限制 - 确保有项目的访问权限 ### TypeScript 类型生成失败 1. 检查 OpenAPI 文档格式是否正确 2. 确保安装了所有必需的依赖 ## 类型安全的 API 调用 本工具不仅可以导出 Swagger 文档,还提供了一套完整的类型安全 API 调用系统,支持 Axios 和 React Query 等流行库。 ### 🚀 特性 - **完全类型安全**: 基于 TypeScript 和 OpenAPI 规范的完整类型推断 - **makeURL 函数**: 类型安全的 URL 和 HTTP 方法组合 - **Axios 支持**: 提供类型化的 Axios 客户端 - **React Query 支持**: 完整的 React Query hooks 和配置 - **自动补全**: IDE 中的完整智能提示 - **运行时安全**: 减少 API 调用错误 ### 📦 额外依赖 根据需要安装以下依赖: ```bash # Axios 支持(可选) npm install axios # React Query 支持(可选) npm install @tanstack/react-query ``` ### 🎯 快速开始 #### 1. 导出 API 类型 首先使用命令行工具导出 API 类型: ```bash # 导出 API 文档和类型 apifox-swagger --projectId 2364643 --outdir ./src/api ``` 这会在 `./src/api/swagger/` 目录下生成: - `all.json`: OpenAPI/Swagger JSON 文档 - `all.ts`: TypeScript 类型定义文件 #### 2. 使用类型安全的 API 调用 ```typescript import { makeURL, createTypedAxiosClient } from '@shixinde/apifox-swagger/api-types'; import { paths } from './api/swagger/all'; // 导入生成的类型 // 创建类型安全的端点 const getUsersEndpoint = makeURL('/api/users', 'get'); const createUserEndpoint = makeURL('/api/users', 'post'); const getUserEndpoint = makeURL('/api/users/{id}', 'get'); // 方式1: 使用现有的 axios 实例 import axios from 'axios'; const axiosInstance = axios.create({ baseURL: 'https://api.example.com', timeout: 5000, headers: { 'Authorization': 'Bearer your-token' } }); const apiClient = createTypedAxiosClient<paths>(axiosInstance); // 方式2: 使用配置对象创建客户端 const apiClient2 = createTypedAxiosClientWithConfig<paths>(axios, { baseURL: 'https://api.example.com', timeout: 5000, headers: { 'Authorization': 'Bearer your-token' } }); // 方式3: 同步创建(与方式2相同,但更明确) const apiClient3 = createTypedAxiosClientSync<paths>(axios, { baseURL: 'https://api.example.com', timeout: 5000, headers: { 'Authorization': 'Bearer your-token' } }); // 类型安全的 API 调用 async function fetchUsers() { const response = await apiClient.get(getUsersEndpoint, { queryParams: { page: 1, limit: 10 } }); // response.data 是完全类型化的 console.log(response.data.users); // 自动推断类型 return response.data; } async function createUser(userData: { name: string; email: string }) { const response = await apiClient.post(createUserEndpoint, { body: userData }); return response.data; // 返回类型自动推断 } async function fetchUser(id: number) { const response = await apiClient.get(getUserEndpoint, { pathParams: { id } }); return response.data; } ``` #### 3. React Query 集成 ```typescript import { useQuery, useMutation } from '@tanstack/react-query'; import { createReactQueryFactory } from '@shixinde/apifox-swagger/api-types'; import axios from 'axios'; // 创建 React Query 工厂 const queryFactory = createReactQueryFactory<paths>( axios.create({ baseURL: 'https://api.example.com' }) ); // React Query Hook - 获取用户列表 function useUsers(page: number = 1, limit: number = 10) { const queryConfig = queryFactory.createQuery( getUsersEndpoint, { pathParams: undefined, queryParams: { page, limit } }, { staleTime: 5 * 60 * 1000, // 5 分钟 cacheTime: 10 * 60 * 1000, // 10 分钟 } ); return useQuery(queryConfig); } // React Query Mutation - 创建用户 function useCreateUser() { const mutationConfig = queryFactory.createMutation( createUserEndpoint, { onSuccess: (data) => { console.log('用户创建成功:', data); }, onError: (error) => { console.error('用户创建失败:', error); } } ); return useMutation(mutationConfig); } ``` #### 4. React 组件中使用 ```tsx import React from 'react'; function UserList() { const { data: usersData, isLoading, error } = useUsers(1, 10); const createUserMutation = useCreateUser(); const handleCreateUser = () => { createUserMutation.mutate({ body: { name: 'John Doe', email: 'john@example.com' } }); }; if (isLoading) return <div>加载中...</div>; if (error) return <div>错误: {error.message}</div>; return ( <div> <h1>用户列表</h1> <button onClick={handleCreateUser}>创建用户</button> {usersData?.users.map(user => ( <div key={user.id}> <span>{user.name} ({user.email})</span> </div> ))} <p>总计: {usersData?.total} 个用户</p> </div> ); } ``` ### 🔧 API 参考 #### makeURL 函数 ```typescript function makeURL<U extends keyof Paths, M extends InferMethodFromPaths<U>>( url: U, method: M ): readonly [U, M] ``` 创建类型安全的 URL 和 HTTP 方法组合。 #### createTypedAxiosClient 函数 ```typescript function createTypedAxiosClient<TPaths extends Paths>( axiosInstance: AxiosInstance, baseURL?: string ): TypedAxiosClient<TPaths> ``` 使用现有的 axios 实例创建类型安全的客户端。 #### createTypedAxiosClientWithConfig 函数 ```typescript function createTypedAxiosClientWithConfig<TPaths extends Paths>( axios: any, config: AxiosRequestConfig & { baseURL?: string } ): TypedAxiosClient<TPaths> ``` 使用 axios 库和配置对象创建类型安全的客户端。 #### createTypedAxiosClientSync 函数 ```typescript function createTypedAxiosClientSync<TPaths extends Paths>( axios: any, config: AxiosRequestConfig & { baseURL?: string } ): TypedAxiosClient<TPaths> ``` 同步方式使用 axios 库和配置对象创建类型安全的客户端。 #### TypedAxiosClient 提供以下类型安全的方法: - `get(endpoint, options?)`: GET 请求 - `post(endpoint, options?)`: POST 请求 - `put(endpoint, options?)`: PUT 请求 - `patch(endpoint, options?)`: PATCH 请求 - `delete(endpoint, options?)`: DELETE 请求 #### ReactQueryFactory 提供以下方法: - `createQuery(endpoint, params?, options?)`: 创建查询配置 - `createMutation(endpoint, options?)`: 创建变更配置 - `createInfiniteQuery(endpoint, params?, options?)`: 创建无限查询配置 ### 🛠️ 高级用法 #### 自定义错误处理 ```typescript import axios from 'axios'; // 创建带有拦截器的 axios 实例 const axiosInstance = axios.create({ baseURL: 'https://api.example.com' }); // 添加响应拦截器 axiosInstance.interceptors.response.use( (response) => response, (error) => { if (error.response?.status === 401) { window.location.href = '/login'; } return Promise.reject(error); } ); // 创建类型安全的客户端 const apiClient = createTypedAxiosClient<paths>(axiosInstance); ``` #### 批量操作 ```typescript async function batchCreateUsers(users: Array<{ name: string; email: string }>) { const results = await Promise.allSettled( users.map(user => apiClient.post(createUserEndpoint, { body: user })) ); const successful = results.filter(result => result.status === 'fulfilled'); const failed = results.filter(result => result.status === 'rejected'); return { successful, failed }; } ``` ### 🚨 注意事项 1. **类型文件更新**: 当 API 更新时,重新运行导出命令更新类型文件 2. **依赖安装**: 根据需要安装 `axios``@tanstack/react-query` 3. **TypeScript 配置**: 确保 TypeScript 配置支持严格模式 4. **路径映射**: 可能需要在 `tsconfig.json` 中配置路径映射 ## 许可证 MIT ## 贡献 欢迎提交 Issue 和 Pull Request!