swagger_generator_flutter/README.md

395 lines
13 KiB
Markdown
Raw Permalink 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.

# 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/<version>/`,类名自动添加 `V2`/`V3` 后缀v1 保持不变)
- `included_tags` / `excluded_tags``ignored_directories` / `ignored_files` 可通过配置或 CLI 控制生成范围
- 模型按用途分类生成request/result/enums/parameters分页响应优先用统一的 `BasePageResult<T>`
- `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/<version>/` 下,模型分类在 `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<void> 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 = <String, (Object value, DateTime expireAt)>{};
T? get<T>(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<BaseResult<UserLoginResult>> userLogin(
@Body() LoginRequest request // 仅当 swagger 中明确定义时
);
// 健康检查接口
@GET('/health')
Future<BaseResult<void>> healthCheck();
// 无明确 schema 的接口
@POST('/api/v1/Action/DoSomething')
Future<BaseResult<Map<String, dynamic>>> doSomething();
```
### **❌ 避免的错误做法**
```dart
// 错误:生成不存在的类型
Future<BaseResult<TaskInfoResult>> someMethod();
// 错误:添加 swagger 中未定义的参数
@POST('/api/v1/GetUsers')
Future<BaseResult<List<User>>> getUsers(
@Body() Map<String, dynamic> 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