# XY Swagger Generator 基于 Swagger/OpenAPI 的 Dart/Flutter API/模型代码生成工具。 [![Dart](https://img.shields.io/badge/Dart-3.0+-blue.svg)](https://dart.dev/) [![Flutter](https://img.shields.io/badge/Flutter-3.0+-blue.svg)](https://flutter.dev/) [![OpenAPI](https://img.shields.io/badge/OpenAPI-3.0+-green.svg)](https://spec.openapis.org/oas/v3.0.3/) ## ✨ 功能特性 ### 🚀 核心功能 - **完整的 OpenAPI 3.0 支持**:涵盖所有主要规范特性 - **高性能解析**:支持并行解析和流式处理大型文档 - **智能代码生成**:生成高质量的 Dart/Flutter 代码 - **模块化架构**:按 API 模块自动分组生成 ### 🎯 专为 Flutter 优化 - **Dio + Retrofit 集成**:完美适配主流网络架构 - **现代数据模型 (Freezed)**:生成基于 Freezed 的不可变数据模型,自动获得 `copyWith`、`toString`、`==/hashCode` 等功能。 - **类型安全**:生成强类型的 API 接口和模型 - **JSON 序列化**:与 `json_serializable` 无缝集成,自动生成序列化代码 - **文件上传支持**:完整的 multipart/form-data 支持 ### 🔧 高级特性 - **智能缓存**:提升重复操作性能 - **错误诊断**:详细的错误报告和修复建议 - **性能监控**:内置性能统计和优化 - **增量生成**:支持增量更新和变更检测 - **枚举键名映射** ⭐NEW: 支持 `x-enum-varnames` 扩展字段和配置文件映射,生成有意义的枚举键名 ## 🔍 当前状态要点 - 版本 **3.0.0**,命令入口统一为 `dart run swagger_generator_flutter generate` - 支持从多个 `swagger_urls` 依次解析并按顺序合并,后者覆盖前者 - 生成的 API 会按版本落在 `api//`,类名自动添加 `V2`/`V3` 后缀(v1 保持不变) - `included_tags` / `excluded_tags` 和 `ignored_directories` / `ignored_files` 可通过配置或 CLI 控制生成范围 - 模型按用途分类生成(request/result/enums/parameters),分页响应优先用统一的 `BasePageResult` - `generator_config.yaml` 放在哪里就按该目录解析相对路径,便于在宿主项目中以 dev dependency 使用 ## 📚 **文档和规范** ### **核心文档** - [**项目概览**](./docs/PROJECT_OVERVIEW.md) - 架构与功能总览 - [**使用指南**](./docs/USAGE_GUIDE.md) - 生成流程与最佳实践 - [**API 参考**](./docs/API_REFERENCE.md) - 核心类型与生成器说明 - [**快速参考**](./QUICK_REFERENCE.md) - 常见问题与命令速查 - [**配置模板**](./generator_config.template.yaml) - 复制为 `generator_config.yaml` 后按需调整 ### **枚举键名映射** ⭐NEW - [**快速参考**](./ENUM_QUICK_REFERENCE.md) - 枚举键名生成的三种方式对比 - [**使用指南**](./ENUM_KEY_NAMES_USAGE.md) - 详细的使用说明和后端实现示例 - [**实现总结**](./ENUM_CONFIG_MAPPING_SUMMARY.md) - 功能实现细节和测试验证 - [**配置示例**](./example/enum_config_mapping_example.yaml) - 完整的配置文件示例 ### **设计原则** 1. **OpenAPI 3.0 标准优先** - 严格遵循规范,不进行主观推断 2. **与服务器保持一致** - swagger.json 是唯一真实来源 3. **有问题沟通文档** - 发现问题时要求完善后端文档 4. **类型安全第一** - 生成强类型代码,避免运行时错误 ## 🚀 快速开始 ### 📦 作为 dev_dependencies 使用(推荐) 1) 在宿主项目 `pubspec.yaml` 添加依赖 ```yaml dependencies: # Freezed 模型需要 freezed_annotation: ^2.4.1 json_annotation: ^4.8.1 dev_dependencies: swagger_generator_flutter: git: url: https://github.com/your-org/swagger_generator_flutter.git ref: main # 或在开发阶段使用本地路径 # swagger_generator_flutter: # path: ../swagger_generator_flutter # 代码生成工具 build_runner: ^2.4.7 freezed: ^2.4.7 json_serializable: ^6.7.1 retrofit_generator: ^8.0.0 # 如果使用 Retrofit ``` 2) 在宿主项目根目录准备 `generator_config.yaml`(复制 `generator_config.template.yaml`) 重点字段: - `input.swagger_urls`:可配置多个 URL,后面的会覆盖前面的同名模型/路径(适合 v1 → v2 迭代) - `output.base_dir/api_dir/models_dir`:输出目录,支持相对路径(基于配置文件所在目录) - `output.included_tags / excluded_tags` 与 `ignored_directories / ignored_files`:控制生成范围和跳过文件 - `generation.api.version_extraction`:自定义版本提取正则与默认版本 - `generation.api.client`:设置 ApiClient 类名/文件名 - `generation.api.base_result_import / base_page_result_import`:接入自定义响应包装类型 3) 生成代码(两步) ```bash # 步骤 1: 生成 Swagger API 和 Freezed 模型定义 flutter pub get dart run swagger_generator_flutter generate --all # 步骤 2: 运行 build_runner 生成 Freezed 和 json_serializable 的 part 文件 dart run build_runner build --delete-conflicting-outputs ``` CLI 里的 `--included-tags/--excluded-tags/--split-by-tags` 优先级高于配置文件。生成结果会按照版本落在 `api//` 下,模型分类在 `api_models/`。 4) 参考示例 `example/` 目录包含可直接运行的示例与 Makefile/generate_api.* 脚本,演示 dev dependency 场景。 ### 💻 独立项目使用 1) 安装依赖 ```bash flutter pub get ``` 2) 直接运行 CLI(可继续使用仓库内的 `generator_config.yaml` 配置) ```bash dart run swagger_generator_flutter generate --all # 或指定本地文件:在 swagger_urls 中写入 file:///absolute/path/to/swagger.json ``` 3) 生成序列化文件 ```bash dart run build_runner build --delete-conflicting-outputs ``` ### 🧩 编程式用法 ```dart import 'dart:io'; import 'package:swagger_generator_flutter/pipeline/parse/swagger_data_parser.dart'; import 'package:swagger_generator_flutter/pipeline/generate/impl/retrofit_api_generator.dart'; Future main() async { // 解析本地或远程的 Swagger 文档(支持 file:// 与 http(s)://) final parser = SwaggerDataParser(); final document = await parser.fetchAndParseSwaggerDocument( 'file:///absolute/path/to/swagger.json', ); // 生成 Dio + Retrofit 风格的 API final generator = RetrofitApiGenerator( className: 'ApiService', useRetrofit: true, useDio: true, splitByTags: true, versionedApi: true, ); final code = generator.generateFromDocument(document); await File('lib/api/api_service.dart').writeAsString(code); } ``` ## 📖 详细配置 ### CLI 命令选项 #### 基本选项 - `--all` / `-a`: 生成所有文件(API + 模型 + 文档) - `--api` / `-r`: 只生成 Retrofit 风格 API 接口 - `--models` / `-m`: 只生成数据模型 - `--docs` / `-d`: 只生成 API 文档 - `--split-by-tags` / `-t`: 按 tags 分组生成多个 API 文件(默认启用) - `--output-dir` / `-o`: 指定输出目录(默认:generator) #### 高级选项 - `--included-tags` / `-i`: 只生成指定 tags 的 API 和模型 - `--excluded-tags` / `-e`: 从生成中排除指定的 tags **示例:** ```bash # 只生成 User 和 Pet 相关的 API 和模型 dart run swagger_generator_flutter generate --all --included-tags=User,Pet # 只生成 Store 相关的 API dart run swagger_generator_flutter generate --api --included-tags=Store # 生成多个指定 tags dart run swagger_generator_flutter generate --all -i User,Pet,Order,Payment ``` **行为说明:** - 如果某个 endpoint 有多个 tags,只要其中一个 tag 在 `included_tags` 列表中,就会生成该 endpoint - 只生成被选中的 endpoints 所引用的 models,避免生成未使用的 model 代码 - 与 `split-by-tags` 选项完全兼容 ### 配置文件选项 #### API Client 配置 可以在 `generator_config.yaml` 中自定义主 API 客户端的类名和文件名: ```yaml generation: api: enabled: true use_retrofit: true use_dio: true # API Client 配置 client: class_name: "ApiClient" # API 客户端类名(默认: ApiClient) file_name: "api_client" # API 客户端文件名(默认: api_client) ``` **使用场景:** - **多项目/模块**:避免命名冲突,如 `ShopApiClient`、`UserApiClient` - **项目规范**:符合团队命名规范,如 `AppApiService`、`NetworkClient` - **模块化开发**:按模块划分,如 `PaymentModuleApi`、`OrderModuleApi` **示例:** ```yaml # 示例 1: 电商项目 client: class_name: "ShopApiClient" file_name: "shop_api_client" # 示例 2: 用户模块 client: class_name: "UserModuleApi" file_name: "user_module_api" # 示例 3: 应用级 API client: class_name: "AppApiService" file_name: "app_api_service" ``` **生成结果:** ```dart // 文件: lib/generated/api/shop_api_client.dart class ShopApiClient { final Dio _dio; ShopApiClient(this._dio) { _initApis(); } // ... API 方法 } ``` 📖 **更多示例**:查看 [API Client 配置示例](./examples/api_client_config_example.yaml) ### 生成器类型 #### 1. RetrofitApiGenerator(基础版) ```dart final generator = RetrofitApiGenerator( className: 'ApiService', // 生成的类名 splitByTags: true, // 是否按标签分割(默认启用) useRetrofit: true, // 使用 Retrofit 注解 generateModels: true, // 生成模型类 ); ``` ### 解析器配置 ```dart final parser = PerformanceParser( config: ParseConfig( enableParallelParsing: true, // 并行解析 enableStreamParsing: false, // 流式解析 enableCaching: true, // 缓存 maxConcurrency: 4, // 最大并发数 enablePerformanceStats: true, // 性能统计 ), ); ``` ### 验证和错误处理 ```dart // 创建验证器 final validator = EnhancedValidator( strictMode: false, // 严格模式 includeWarnings: true, // 包含警告 ); // 验证文档 final isValid = validator.validateDocument(document); // 获取错误报告 final errorReport = validator.errorReporter.generateReport(); print(errorReport); ``` ## 📊 性能优化 ### 缓存策略 当前版本不再内置 SmartCache。建议在业务层按需实现缓存(如内存 Map + 过期时间)或使用第三方库。示例: ```dart class SimpleCache { final _store = {}; T? get(String key) { final entry = _store[key]; if (entry == null) return null; if (DateTime.now().isAfter(entry.$2)) { _store.remove(key); return null; } return entry.$1 as T; } void put(String key, Object value, {Duration ttl = const Duration(minutes: 30)}) { _store[key] = (value, DateTime.now().add(ttl)); } } ``` ### 性能监控 ```dart // 获取解析性能统计 final parseStats = parser.lastStats; print('解析性能统计:'); print(' 总时间: ${parseStats?.totalTime.inMilliseconds}ms'); print(' 路径数: ${parseStats?.pathCount}'); print(' 吞吐量: ${parseStats?.bytesPerSecond.toStringAsFixed(2)} bytes/s'); ``` ## 📁 目录结构 ``` swagger_generator_flutter/ bin/ # CLI 入口(main & swagger_generator_flutter) docs/ # 项目文档(概览、使用指南、API 参考) example/ # dev dependency 场景示例(含 make / 脚本) generator/ # 默认输出目录示例(生成的文档) lib/ # 核心代码 commands/ # CLI 命令(GenerateCommand 等) core/ # 配置、模型、异常 pipeline/ # 核心处理流程 (Parse -> Validate -> Generate -> Render -> Output) utils/ # FileUtils、StringUtils 等 tests/ # 基础测试示例 generator_config.template.yaml ``` ## 运行测试 ```bash dart run test tests/ ``` ## 🎯 **规范遵循示例** ### **✅ 正确的生成结果** ```dart // 严格按照 swagger.json 定义生成 @POST('/api/v1/Login/userLogin') Future> userLogin( @Body() LoginRequest request // 仅当 swagger 中明确定义时 ); // 健康检查接口 @GET('/health') Future> healthCheck(); // 无明确 schema 的接口 @POST('/api/v1/Action/DoSomething') Future>> doSomething(); ``` ### **❌ 避免的错误做法** ```dart // 错误:生成不存在的类型 Future> someMethod(); // 错误:添加 swagger 中未定义的参数 @POST('/api/v1/GetUsers') Future>> getUsers( @Body() Map request // swagger 中没有定义 ); // 错误:基于关键词推断类型 if (path.contains('login')) return 'UserLoginResult'; ``` ## 贡献指南 - 在提交前请先跑通 `dart run swagger_generator_flutter generate --all` 与必要的 `build_runner` - 参考 [docs/USAGE_GUIDE.md](./docs/USAGE_GUIDE.md) 和 [QUICK_REFERENCE.md](./QUICK_REFERENCE.md) 保持生成规则一致 - 新增能力需补充最小可复现示例或测试 - 生成规则/命名风格如有特殊需求请在 issue 说明并同步更新文档 ## 常见问题 - **生成的类型不存在?** 检查 swagger.json 中是否定义了对应的 schema - **接口缺少参数?** 确认 swagger.json 中是否有完整的参数定义 - **可空性不正确?** 检查 swagger.json 中的 nullable 字段设置 - 更多问题请参考 [快速参考指南](./QUICK_REFERENCE.md) ### 命令行提示 - 查看所有选项:`dart run swagger_generator_flutter generate --help` - 旧版 `run_swagger.sh/.bat` 已移除,统一使用 `dart run` 入口 --- 更新日期:2025-11-09 作者:Max