459 lines
11 KiB
Markdown
459 lines
11 KiB
Markdown
# Augment 代码生成规范
|
||
## 基于 OpenAPI 3.0 标准的 Flutter API 代码生成规范
|
||
|
||
### 📋 **核心原则**
|
||
|
||
#### 1. **OpenAPI 3.0 标准优先**
|
||
- **严格遵循 OpenAPI 3.0 规范**
|
||
- **swagger.json 是唯一真实来源**
|
||
- **不进行主观推断或猜测**
|
||
- **有问题与服务器端沟通完善文档**
|
||
|
||
#### 2. **类型安全第一**
|
||
- **所有类型必须从 schema 定义中提取**
|
||
- **禁止硬编码类型映射**
|
||
- **使用强类型,避免 dynamic**
|
||
- **严格的可空性控制**
|
||
|
||
#### 3. **一致性保证**
|
||
- **统一的命名规范**
|
||
- **统一的文件结构**
|
||
- **统一的代码风格**
|
||
- **统一的注释格式**
|
||
|
||
---
|
||
|
||
## 🏗️ **项目结构规范**
|
||
|
||
### **目录结构**
|
||
```
|
||
generator/
|
||
├── api/ # API 接口文件
|
||
│ ├── api_client.dart # 主 API 客户端
|
||
│ ├── login_api.dart # 按 tag 分组的 API
|
||
│ └── ...
|
||
├── api_models/ # 数据模型
|
||
│ ├── index.dart # 统一导出文件
|
||
│ ├── user_result.dart # 具体模型类
|
||
│ └── ...
|
||
├── api_paths.dart # API 路径常量
|
||
├── build.yaml # 构建配置
|
||
└── pubspec.yaml # 依赖配置
|
||
```
|
||
|
||
### **文件命名规范**
|
||
- **API 文件**: `{tag_name}_api.dart` (snake_case)
|
||
- **模型文件**: `{schema_name}.dart` (snake_case)
|
||
- **参数文件**: `{operation_id}_parameters.dart`
|
||
- **类名**: `PascalCase`
|
||
- **方法名**: `camelCase`
|
||
- **常量**: `UPPER_SNAKE_CASE`
|
||
|
||
---
|
||
|
||
## 🔧 **代码生成规范**
|
||
|
||
### **1. API 接口生成**
|
||
|
||
#### **基本结构**
|
||
```dart
|
||
// {Tag} API 接口定义
|
||
// 基于 Swagger API 文档: {swagger_url}
|
||
// 由 xy_swagger_generator by max 生成
|
||
// Copyright (C) 2025 YuanXuan. All rights reserved.
|
||
|
||
import 'package:dio/dio.dart';
|
||
import 'package:retrofit/retrofit.dart';
|
||
import 'package:learning_officer_oa/common/models/common/base_result.dart';
|
||
|
||
// 按需导入分页类型
|
||
import 'package:learning_officer_oa/common/models/common/base_page_result.dart';
|
||
|
||
part '{tag_name}_api.g.dart';
|
||
|
||
/// {Tag} API 接口
|
||
/// 负责处理 {Tag} 相关的接口
|
||
@RestApi(parser: Parser.JsonSerializable)
|
||
abstract class {Tag}Api {
|
||
factory {Tag}Api(Dio dio, {String? baseUrl}) = _{Tag}Api;
|
||
}
|
||
```
|
||
|
||
#### **方法生成规则**
|
||
```dart
|
||
/// {summary}
|
||
@{HTTP_METHOD}('{path}')
|
||
Future<{ReturnType}> {methodName}(
|
||
// 路径参数
|
||
@Path('{param}') {Type} param,
|
||
// 查询参数
|
||
@Query('{param}') {Type}? param,
|
||
// 请求体(仅当 swagger 中明确定义时)
|
||
@Body() {Type} request
|
||
);
|
||
```
|
||
|
||
### **2. 返回类型规范**
|
||
|
||
#### **类型提取优先级**
|
||
1. **从 responses.200.content.application/json.schema 提取**
|
||
2. **从 responses.200.content.text/plain.schema 提取**
|
||
3. **特殊处理**: 健康检查接口返回 `BaseResult<void>`
|
||
4. **默认**: `BaseResult<Map<String, dynamic>>`
|
||
|
||
#### **分页类型判断**
|
||
```dart
|
||
// 当返回类型包含分页结构时使用 BasePageResult
|
||
BasePageResult<{ItemType}>
|
||
|
||
// 判断依据:
|
||
// 1. schema 中包含 pageIndex, pageSize, totalCount 等字段
|
||
// 2. 查询参数中包含分页参数 (page, size, limit 等)
|
||
```
|
||
|
||
### **3. 请求体生成规范**
|
||
|
||
#### **添加 @Body() 的条件**
|
||
```dart
|
||
// 仅在以下情况添加 @Body() 参数:
|
||
// 1. requestBody 在 swagger 中明确定义
|
||
// 2. parameters 中存在 in: "body" 的参数
|
||
// 3. 其他情况一律不添加
|
||
```
|
||
|
||
#### **请求体类型提取**
|
||
```dart
|
||
// 优先级:
|
||
// 1. requestBody.content.application/json.schema
|
||
// 2. requestBody.content.text/plain.schema
|
||
// 3. 默认: Map<String, dynamic>
|
||
```
|
||
|
||
---
|
||
|
||
## 📝 **数据模型生成规范**
|
||
|
||
### **1. 模型类结构**
|
||
|
||
#### **基本模板**
|
||
```dart
|
||
// {schemaName} 模型定义
|
||
// 基于 Swagger API 文档: {swagger_url}
|
||
// 由 xy_swagger_generator by max 生成
|
||
// Copyright (C) 2025 YuanXuan. All rights reserved.
|
||
|
||
import 'package:json_annotation/json_annotation.dart';
|
||
import 'index.dart';
|
||
|
||
part '{schema_name}.g.dart';
|
||
|
||
@JsonSerializable(checked: true, includeIfNull: false)
|
||
class {SchemaName} {
|
||
// 属性定义
|
||
|
||
const {SchemaName}({
|
||
// 构造函数参数
|
||
});
|
||
|
||
factory {SchemaName}.fromJson(Map<String, dynamic> json) =>
|
||
_${SchemaName}FromJson(json);
|
||
|
||
Map<String, dynamic> toJson() => _${SchemaName}ToJson(this);
|
||
}
|
||
```
|
||
|
||
### **2. 属性生成规则**
|
||
|
||
#### **可空性判断**
|
||
```dart
|
||
// 严格按照 OpenAPI 规范:
|
||
// 1. 有 "nullable": true -> 可空类型 (Type?)
|
||
// 2. 没有 "nullable": true -> 非空类型 (Type)
|
||
// 3. 忽略 required 字段,只看 nullable
|
||
|
||
final String name; // 非空
|
||
final String? nickname; // 可空 (nullable: true)
|
||
```
|
||
|
||
#### **类型映射**
|
||
```dart
|
||
// OpenAPI -> Dart 类型映射
|
||
"string" -> String
|
||
"integer" -> int
|
||
"number" -> double
|
||
"boolean" -> bool
|
||
"array" -> List<T>
|
||
"object" -> Map<String, dynamic> 或具体类型
|
||
"$ref" -> 引用的具体类型
|
||
```
|
||
|
||
#### **构造函数规则**
|
||
```dart
|
||
const {ClassName}({
|
||
required this.nonNullableField, // 非空字段必须 required
|
||
this.nullableField, // 可空字段不需要 required
|
||
});
|
||
```
|
||
|
||
### **3. 导入管理**
|
||
|
||
#### **按需导入原则**
|
||
```dart
|
||
// 只导入实际使用的类型
|
||
// 分页相关
|
||
import 'package:learning_officer_oa/common/models/common/base_page_result.dart';
|
||
|
||
// 基础响应
|
||
import 'package:learning_officer_oa/common/models/common/base_result.dart';
|
||
|
||
// 模型类型
|
||
import '../../api_models/{model_name}.dart';
|
||
```
|
||
|
||
---
|
||
|
||
## 🚫 **禁止事项**
|
||
|
||
### **1. 硬编码推断**
|
||
```dart
|
||
// ❌ 禁止基于路径关键词推断类型
|
||
if (path.contains('login')) return 'UserLoginResult';
|
||
|
||
// ❌ 禁止基于 tag 推断类型
|
||
if (tag.contains('task')) return 'TaskInfoResult';
|
||
|
||
// ❌ 禁止基于操作推断请求体
|
||
if (method == 'POST') addBody();
|
||
```
|
||
|
||
### **2. 不存在的类型**
|
||
```dart
|
||
// ❌ 禁止生成 swagger 中不存在的类型
|
||
Future<BaseResult<TaskInfoResult>> // TaskInfoResult 不存在
|
||
|
||
// ✅ 使用通用类型或实际存在的类型
|
||
Future<BaseResult<Map<String, dynamic>>>
|
||
Future<BaseResult<ActualExistingType>>
|
||
```
|
||
|
||
### **3. 主观判断**
|
||
```dart
|
||
// ❌ 禁止主观添加参数
|
||
@Body() Map<String, dynamic> request // swagger 中没有定义
|
||
|
||
// ❌ 禁止主观修改类型
|
||
List<dynamic> -> List<SpecificType> // 没有明确的 items schema
|
||
```
|
||
|
||
---
|
||
|
||
## ✅ **质量保证**
|
||
|
||
### **1. 生成前检查**
|
||
- **验证 swagger.json 格式正确性**
|
||
- **检查所有 $ref 引用完整性**
|
||
- **确认 components/schemas 定义完整**
|
||
|
||
### **2. 生成后验证**
|
||
- **所有生成的类型在 swagger 中都有定义**
|
||
- **没有硬编码的类型映射**
|
||
- **导入语句按需生成**
|
||
- **代码通过 dart analyze 检查**
|
||
|
||
### **3. 错误处理**
|
||
```dart
|
||
// 当 swagger 定义不完整时的处理策略:
|
||
// 1. 记录警告日志
|
||
// 2. 使用安全的默认类型
|
||
// 3. 提示完善 swagger 文档
|
||
// 4. 不进行主观推断
|
||
```
|
||
|
||
---
|
||
|
||
## 📞 **沟通机制**
|
||
|
||
### **文档问题反馈**
|
||
1. **发现 swagger 定义缺失** -> 联系后端完善
|
||
2. **类型定义不明确** -> 要求明确 schema
|
||
3. **响应结构不一致** -> 统一响应格式
|
||
4. **参数定义缺失** -> 补充参数说明
|
||
|
||
### **版本管理**
|
||
- **swagger.json 版本控制**
|
||
- **生成代码版本标记**
|
||
- **变更日志记录**
|
||
- **向后兼容性检查**
|
||
|
||
---
|
||
|
||
## 🛠️ **工具配置规范**
|
||
|
||
### **1. 生成器配置**
|
||
```yaml
|
||
# pubspec.yaml
|
||
dependencies:
|
||
dio: ^5.0.0
|
||
retrofit: ^4.0.0
|
||
json_annotation: ^4.8.0
|
||
|
||
dev_dependencies:
|
||
build_runner: ^2.3.0
|
||
retrofit_generator: ^8.0.0
|
||
json_serializable: ^6.6.0
|
||
```
|
||
|
||
### **2. 构建配置**
|
||
```yaml
|
||
# build.yaml
|
||
targets:
|
||
$default:
|
||
builders:
|
||
json_serializable:
|
||
options:
|
||
checked: true
|
||
include_if_null: false
|
||
explicit_to_json: true
|
||
```
|
||
|
||
### **3. 分析配置**
|
||
```yaml
|
||
# analysis_options.yaml
|
||
analyzer:
|
||
strong-mode:
|
||
implicit-casts: false
|
||
implicit-dynamic: false
|
||
|
||
linter:
|
||
rules:
|
||
- prefer_const_constructors
|
||
- prefer_final_fields
|
||
- avoid_dynamic_calls
|
||
```
|
||
|
||
---
|
||
|
||
## 📚 **最佳实践示例**
|
||
|
||
### **1. 标准 API 接口**
|
||
```dart
|
||
/// 用户登录
|
||
@POST('/api/v1/Login/userLogin')
|
||
Future<BaseResult<UserLoginResult>> userLogin(
|
||
@Body() LoginRequest request
|
||
);
|
||
|
||
/// 获取用户列表(分页)
|
||
@GET('/api/v1/User/GetUserList')
|
||
Future<BasePageResult<UserResult>> getUserList(
|
||
@Query('page') int page,
|
||
@Query('size') int size,
|
||
@Query('keyword') String? keyword
|
||
);
|
||
|
||
/// 健康检查
|
||
@GET('/health')
|
||
Future<BaseResult<void>> healthCheck();
|
||
|
||
/// 无明确 schema 的接口
|
||
@POST('/api/v1/Action/DoSomething')
|
||
Future<BaseResult<Map<String, dynamic>>> doSomething();
|
||
```
|
||
|
||
### **2. 标准数据模型**
|
||
```dart
|
||
@JsonSerializable(checked: true, includeIfNull: false)
|
||
class UserResult {
|
||
/// 用户ID
|
||
final int id;
|
||
|
||
/// 用户名
|
||
final String username;
|
||
|
||
/// 昵称(可空)
|
||
final String? nickname;
|
||
|
||
/// 头像URL(可空)
|
||
final String? avatarUrl;
|
||
|
||
/// 是否激活
|
||
final bool isActive;
|
||
|
||
const UserResult({
|
||
required this.id,
|
||
required this.username,
|
||
this.nickname,
|
||
this.avatarUrl,
|
||
required this.isActive,
|
||
});
|
||
|
||
factory UserResult.fromJson(Map<String, dynamic> json) =>
|
||
_$UserResultFromJson(json);
|
||
|
||
Map<String, dynamic> toJson() => _$UserResultToJson(this);
|
||
}
|
||
```
|
||
|
||
### **3. 参数类生成**
|
||
```dart
|
||
@JsonSerializable(checked: true, includeIfNull: false)
|
||
class GetUserListParameters {
|
||
final int page;
|
||
final int size;
|
||
final String? keyword;
|
||
|
||
const GetUserListParameters({
|
||
required this.page,
|
||
required this.size,
|
||
this.keyword,
|
||
});
|
||
|
||
factory GetUserListParameters.fromJson(Map<String, dynamic> json) =>
|
||
_$GetUserListParametersFromJson(json);
|
||
|
||
Map<String, dynamic> toJson() => _$GetUserListParametersToJson(this);
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 🔍 **代码审查清单**
|
||
|
||
### **生成代码检查项**
|
||
- [ ] 所有类型都在 swagger.json 中有定义
|
||
- [ ] 没有硬编码的类型推断
|
||
- [ ] 可空性严格按照 nullable 字段
|
||
- [ ] 导入语句按需生成
|
||
- [ ] 方法参数与 swagger 定义一致
|
||
- [ ] 返回类型正确提取
|
||
- [ ] 注释信息完整
|
||
- [ ] 代码格式规范
|
||
|
||
### **swagger.json 检查项**
|
||
- [ ] 所有接口都有明确的 responses 定义
|
||
- [ ] 所有 schema 都有完整的属性定义
|
||
- [ ] 所有 $ref 引用都存在
|
||
- [ ] 参数定义完整(name, in, schema)
|
||
- [ ] requestBody 定义明确
|
||
- [ ] 版本信息正确
|
||
|
||
---
|
||
|
||
## 📖 **参考资源**
|
||
|
||
### **官方文档**
|
||
- [OpenAPI 3.0 规范](https://swagger.io/specification/)
|
||
- [Retrofit for Dart](https://pub.dev/packages/retrofit)
|
||
- [JSON Serializable](https://pub.dev/packages/json_serializable)
|
||
|
||
### **项目相关**
|
||
- [项目 README](./README.md)
|
||
- [API 参考文档](./docs/API_REFERENCE.md)
|
||
- [贡献指南](./CONTRIBUTING.md)
|
||
|
||
---
|
||
|
||
**最后更新**: 2025-01-24
|
||
**版本**: v2.0
|
||
**维护者**: Augment Team
|