11 KiB
11 KiB
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 接口生成
基本结构
// {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;
}
方法生成规则
/// {summary}
@{HTTP_METHOD}('{path}')
Future<{ReturnType}> {methodName}(
// 路径参数
@Path('{param}') {Type} param,
// 查询参数
@Query('{param}') {Type}? param,
// 请求体(仅当 swagger 中明确定义时)
@Body() {Type} request
);
2. 返回类型规范
类型提取优先级
- 从 responses.200.content.application/json.schema 提取
- 从 responses.200.content.text/plain.schema 提取
- 特殊处理: 健康检查接口返回
BaseResult<void> - 默认:
BaseResult<Map<String, dynamic>>
分页类型判断
// 当返回类型包含分页结构时使用 BasePageResult
BasePageResult<{ItemType}>
// 判断依据:
// 1. schema 中包含 pageIndex, pageSize, totalCount 等字段
// 2. 查询参数中包含分页参数 (page, size, limit 等)
3. 请求体生成规范
添加 @Body() 的条件
// 仅在以下情况添加 @Body() 参数:
// 1. requestBody 在 swagger 中明确定义
// 2. parameters 中存在 in: "body" 的参数
// 3. 其他情况一律不添加
请求体类型提取
// 优先级:
// 1. requestBody.content.application/json.schema
// 2. requestBody.content.text/plain.schema
// 3. 默认: Map<String, dynamic>
📝 数据模型生成规范
1. 模型类结构
基本模板
// {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. 属性生成规则
可空性判断
// 严格按照 OpenAPI 规范:
// 1. 有 "nullable": true -> 可空类型 (Type?)
// 2. 没有 "nullable": true -> 非空类型 (Type)
// 3. 忽略 required 字段,只看 nullable
final String name; // 非空
final String? nickname; // 可空 (nullable: true)
类型映射
// OpenAPI -> Dart 类型映射
"string" -> String
"integer" -> int
"number" -> double
"boolean" -> bool
"array" -> List<T>
"object" -> Map<String, dynamic> 或具体类型
"$ref" -> 引用的具体类型
构造函数规则
const {ClassName}({
required this.nonNullableField, // 非空字段必须 required
this.nullableField, // 可空字段不需要 required
});
3. 导入管理
按需导入原则
// 只导入实际使用的类型
// 分页相关
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. 硬编码推断
// ❌ 禁止基于路径关键词推断类型
if (path.contains('login')) return 'UserLoginResult';
// ❌ 禁止基于 tag 推断类型
if (tag.contains('task')) return 'TaskInfoResult';
// ❌ 禁止基于操作推断请求体
if (method == 'POST') addBody();
2. 不存在的类型
// ❌ 禁止生成 swagger 中不存在的类型
Future<BaseResult<TaskInfoResult>> // TaskInfoResult 不存在
// ✅ 使用通用类型或实际存在的类型
Future<BaseResult<Map<String, dynamic>>>
Future<BaseResult<ActualExistingType>>
3. 主观判断
// ❌ 禁止主观添加参数
@Body() Map<String, dynamic> request // swagger 中没有定义
// ❌ 禁止主观修改类型
List<dynamic> -> List<SpecificType> // 没有明确的 items schema
✅ 质量保证
1. 生成前检查
- 验证 swagger.json 格式正确性
- 检查所有 $ref 引用完整性
- 确认 components/schemas 定义完整
2. 生成后验证
- 所有生成的类型在 swagger 中都有定义
- 没有硬编码的类型映射
- 导入语句按需生成
- 代码通过 dart analyze 检查
3. 错误处理
// 当 swagger 定义不完整时的处理策略:
// 1. 记录警告日志
// 2. 使用安全的默认类型
// 3. 提示完善 swagger 文档
// 4. 不进行主观推断
📞 沟通机制
文档问题反馈
- 发现 swagger 定义缺失 -> 联系后端完善
- 类型定义不明确 -> 要求明确 schema
- 响应结构不一致 -> 统一响应格式
- 参数定义缺失 -> 补充参数说明
版本管理
- swagger.json 版本控制
- 生成代码版本标记
- 变更日志记录
- 向后兼容性检查
🛠️ 工具配置规范
1. 生成器配置
# 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. 构建配置
# build.yaml
targets:
$default:
builders:
json_serializable:
options:
checked: true
include_if_null: false
explicit_to_json: true
3. 分析配置
# 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 接口
/// 用户登录
@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. 标准数据模型
@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. 参数类生成
@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 定义明确
- 版本信息正确
📖 参考资源
官方文档
项目相关
最后更新: 2025-01-24 版本: v2.0 维护者: Augment Team