503 lines
12 KiB
Dart
503 lines
12 KiB
Dart
/// Swagger数据模型定义
|
|
/// 提供类型安全的数据结构
|
|
library;
|
|
|
|
/// HTTP方法枚举
|
|
/// 表示常见的 RESTful API 方法。
|
|
enum HttpMethod {
|
|
/// GET 方法
|
|
get('GET'),
|
|
|
|
/// POST 方法
|
|
post('POST'),
|
|
|
|
/// PUT 方法
|
|
put('PUT'),
|
|
|
|
/// DELETE 方法
|
|
delete('DELETE'),
|
|
|
|
/// PATCH 方法
|
|
patch('PATCH'),
|
|
|
|
/// HEAD 方法
|
|
head('HEAD'),
|
|
|
|
/// OPTIONS 方法
|
|
options('OPTIONS');
|
|
|
|
/// 枚举值对应的字符串
|
|
const HttpMethod(this.value);
|
|
final String value;
|
|
|
|
/// 通过字符串获取 HttpMethod 枚举
|
|
static HttpMethod fromString(String value) {
|
|
return HttpMethod.values.firstWhere(
|
|
(method) => method.value == value.toUpperCase(),
|
|
orElse: () => HttpMethod.get,
|
|
);
|
|
}
|
|
}
|
|
|
|
/// 属性类型枚举
|
|
/// 用于描述 API 属性的数据类型。
|
|
enum PropertyType {
|
|
/// 字符串类型
|
|
string('string'),
|
|
|
|
/// 整数类型
|
|
integer('integer'),
|
|
|
|
/// 浮点数类型
|
|
number('number'),
|
|
|
|
/// 布尔类型
|
|
boolean('boolean'),
|
|
|
|
/// 数组类型
|
|
array('array'),
|
|
|
|
/// 对象类型
|
|
object('object'),
|
|
|
|
/// 文件类型
|
|
file('file'),
|
|
|
|
/// 日期类型
|
|
date('date'),
|
|
|
|
/// 日期时间类型
|
|
dateTime('date-time'),
|
|
|
|
/// 引用类型
|
|
reference('reference'),
|
|
|
|
/// 枚举类型
|
|
enumType('enum');
|
|
|
|
/// 枚举值对应的字符串
|
|
const PropertyType(this.value);
|
|
final String value;
|
|
|
|
/// 通过字符串获取 PropertyType 枚举
|
|
static PropertyType fromString(String value) {
|
|
return PropertyType.values.firstWhere(
|
|
(type) => type.value == value.toLowerCase(),
|
|
orElse: () => PropertyType.string,
|
|
);
|
|
}
|
|
}
|
|
|
|
/// 参数位置枚举
|
|
/// 用于描述 API 参数在请求中的位置。
|
|
enum ParameterLocation {
|
|
/// 查询参数
|
|
query('query'),
|
|
|
|
/// 路径参数
|
|
path('path'),
|
|
|
|
/// 请求头参数
|
|
header('header'),
|
|
|
|
/// 请求体参数
|
|
body('body'),
|
|
|
|
/// 表单参数
|
|
form('formData'),
|
|
|
|
/// Cookie 参数
|
|
cookie('cookie');
|
|
|
|
/// 枚举值对应的字符串
|
|
const ParameterLocation(this.value);
|
|
final String value;
|
|
|
|
/// 通过字符串获取 ParameterLocation 枚举
|
|
static ParameterLocation fromString(String value) {
|
|
return ParameterLocation.values.firstWhere(
|
|
(location) => location.value == value.toLowerCase(),
|
|
orElse: () => ParameterLocation.query,
|
|
);
|
|
}
|
|
}
|
|
|
|
/// Swagger文档信息
|
|
/// 描述整个 API 的元数据和结构。
|
|
class SwaggerDocument {
|
|
/// 文档标题
|
|
final String title;
|
|
|
|
/// 版本号
|
|
final String version;
|
|
|
|
/// 文档描述
|
|
final String description;
|
|
|
|
/// 主机名
|
|
final String host;
|
|
|
|
/// 基础路径
|
|
final String basePath;
|
|
|
|
/// 支持的协议
|
|
final List<String> schemes;
|
|
|
|
/// 支持的请求类型
|
|
final List<String> consumes;
|
|
|
|
/// 支持的响应类型
|
|
final List<String> produces;
|
|
|
|
/// 路径定义
|
|
final Map<String, ApiPath> paths;
|
|
|
|
/// 数据模型定义
|
|
final Map<String, ApiModel> models;
|
|
|
|
/// 控制器定义
|
|
final Map<String, ApiController> controllers;
|
|
|
|
/// 构造函数
|
|
const SwaggerDocument({
|
|
required this.title,
|
|
required this.version,
|
|
required this.description,
|
|
required this.host,
|
|
required this.basePath,
|
|
required this.schemes,
|
|
required this.consumes,
|
|
required this.produces,
|
|
required this.paths,
|
|
required this.models,
|
|
required this.controllers,
|
|
});
|
|
|
|
/// 从JSON创建SwaggerDocument
|
|
factory SwaggerDocument.fromJson(Map<String, dynamic> json) {
|
|
final info = json['info'] as Map<String, dynamic>? ?? {};
|
|
return SwaggerDocument(
|
|
title: info['title'] as String? ?? 'API',
|
|
version: info['version'] as String? ?? '1.0.0',
|
|
description: info['description'] as String? ?? '',
|
|
host: json['host'] as String? ?? '',
|
|
basePath: json['basePath'] as String? ?? '',
|
|
schemes: List<String>.from(json['schemes'] ?? ['https']),
|
|
consumes: List<String>.from(json['consumes'] ?? ['application/json']),
|
|
produces: List<String>.from(json['produces'] ?? ['application/json']),
|
|
paths: {},
|
|
models: {},
|
|
controllers: {},
|
|
);
|
|
}
|
|
}
|
|
|
|
/// API路径信息
|
|
class ApiPath {
|
|
final String path;
|
|
final HttpMethod method;
|
|
final String summary;
|
|
final String description;
|
|
final String operationId;
|
|
final List<String> tags;
|
|
final List<ApiParameter> parameters;
|
|
final Map<String, ApiResponse> responses;
|
|
final ApiRequestBody? requestBody;
|
|
final bool deprecated;
|
|
|
|
const ApiPath({
|
|
required this.path,
|
|
required this.method,
|
|
required this.summary,
|
|
required this.description,
|
|
required this.operationId,
|
|
required this.tags,
|
|
required this.parameters,
|
|
required this.responses,
|
|
this.requestBody,
|
|
this.deprecated = false,
|
|
});
|
|
|
|
/// 从JSON创建ApiPath
|
|
factory ApiPath.fromJson(
|
|
String path,
|
|
String method,
|
|
Map<String, dynamic> json,
|
|
) {
|
|
return ApiPath(
|
|
path: path,
|
|
method: HttpMethod.fromString(method),
|
|
summary: json['summary'] as String? ?? '',
|
|
description: json['description'] as String? ?? '',
|
|
operationId: json['operationId'] as String? ?? '',
|
|
tags: List<String>.from(json['tags'] ?? []),
|
|
parameters: (json['parameters'] as List?)
|
|
?.map((p) => ApiParameter.fromJson(p as Map<String, dynamic>))
|
|
.toList() ??
|
|
[],
|
|
responses: (json['responses'] as Map<String, dynamic>?)?.map(
|
|
(code, response) => MapEntry(
|
|
code,
|
|
ApiResponse.fromJson(code, response as Map<String, dynamic>),
|
|
),
|
|
) ??
|
|
{},
|
|
requestBody: json['requestBody'] != null
|
|
? ApiRequestBody.fromJson(json['requestBody'] as Map<String, dynamic>)
|
|
: null,
|
|
deprecated: json['deprecated'] as bool? ?? false,
|
|
);
|
|
}
|
|
}
|
|
|
|
/// API参数信息
|
|
class ApiParameter {
|
|
final String name;
|
|
final ParameterLocation location;
|
|
final bool required;
|
|
final PropertyType type;
|
|
final String description;
|
|
final String? format;
|
|
final dynamic example;
|
|
final dynamic defaultValue;
|
|
|
|
const ApiParameter({
|
|
required this.name,
|
|
required this.location,
|
|
required this.required,
|
|
required this.type,
|
|
required this.description,
|
|
this.format,
|
|
this.example,
|
|
this.defaultValue,
|
|
});
|
|
|
|
/// 从JSON创建ApiParameter
|
|
factory ApiParameter.fromJson(Map<String, dynamic> json) {
|
|
final schema = json['schema'] as Map<String, dynamic>?;
|
|
final type =
|
|
schema?['type'] as String? ?? json['type'] as String? ?? 'string';
|
|
|
|
return ApiParameter(
|
|
name: json['name'] as String? ?? '',
|
|
location: ParameterLocation.fromString(json['in'] as String? ?? 'query'),
|
|
required: json['required'] as bool? ?? false,
|
|
type: PropertyType.fromString(type),
|
|
description: json['description'] as String? ?? '',
|
|
format: schema?['format'] as String? ?? json['format'] as String?,
|
|
example: json['example'],
|
|
defaultValue: json['default'],
|
|
);
|
|
}
|
|
}
|
|
|
|
/// API响应信息
|
|
class ApiResponse {
|
|
final String code;
|
|
final String description;
|
|
final Map<String, dynamic>? schema;
|
|
final Map<String, dynamic>? content;
|
|
|
|
const ApiResponse({
|
|
required this.code,
|
|
required this.description,
|
|
this.schema,
|
|
this.content,
|
|
});
|
|
|
|
/// 从JSON创建ApiResponse
|
|
factory ApiResponse.fromJson(String code, Map<String, dynamic> json) {
|
|
return ApiResponse(
|
|
code: code,
|
|
description: json['description'] as String? ?? '',
|
|
schema: json['schema'] as Map<String, dynamic>?,
|
|
content: json['content'] as Map<String, dynamic>?,
|
|
);
|
|
}
|
|
}
|
|
|
|
/// API请求体信息
|
|
class ApiRequestBody {
|
|
final String description;
|
|
final bool required;
|
|
final Map<String, dynamic>? content;
|
|
|
|
const ApiRequestBody({
|
|
required this.description,
|
|
required this.required,
|
|
this.content,
|
|
});
|
|
|
|
/// 从JSON创建ApiRequestBody
|
|
factory ApiRequestBody.fromJson(Map<String, dynamic> json) {
|
|
return ApiRequestBody(
|
|
description: json['description'] as String? ?? '',
|
|
required: json['required'] as bool? ?? false,
|
|
content: json['content'] as Map<String, dynamic>?,
|
|
);
|
|
}
|
|
}
|
|
|
|
/// API模型信息
|
|
class ApiModel {
|
|
final String name;
|
|
final String description;
|
|
final Map<String, ApiProperty> properties;
|
|
final List<String> required;
|
|
final bool isEnum;
|
|
final List<dynamic> enumValues;
|
|
final PropertyType? enumType;
|
|
|
|
const ApiModel({
|
|
required this.name,
|
|
required this.description,
|
|
required this.properties,
|
|
required this.required,
|
|
this.isEnum = false,
|
|
this.enumValues = const [],
|
|
this.enumType,
|
|
});
|
|
|
|
/// 从JSON创建ApiModel
|
|
factory ApiModel.fromJson(String name, Map<String, dynamic> json) {
|
|
final isEnum = json['enum'] != null;
|
|
final enumValues = isEnum ? List<dynamic>.from(json['enum']) : <dynamic>[];
|
|
final properties = json['properties'] as Map<String, dynamic>? ?? {};
|
|
List<String> required;
|
|
if (json.containsKey('required')) {
|
|
required = List<String>.from(json['required']);
|
|
} else {
|
|
// 没有 required 字段时,凡 nullable != true 的都视为 required
|
|
required = properties.entries
|
|
.where((e) => !(e.value['nullable'] as bool? ?? false))
|
|
.map((e) => e.key)
|
|
.toList();
|
|
}
|
|
|
|
return ApiModel(
|
|
name: name,
|
|
description: json['description'] as String? ?? '',
|
|
required: required,
|
|
isEnum: isEnum,
|
|
enumValues: enumValues,
|
|
enumType: isEnum
|
|
? PropertyType.fromString(json['type'] as String? ?? 'string')
|
|
: null,
|
|
properties: properties.map(
|
|
(propName, propData) => MapEntry(
|
|
propName,
|
|
ApiProperty.fromJson(
|
|
propName,
|
|
propData as Map<String, dynamic>,
|
|
required,
|
|
),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
}
|
|
|
|
/// API属性信息
|
|
class ApiProperty {
|
|
final String name;
|
|
final PropertyType type;
|
|
final String? format;
|
|
final String description;
|
|
final bool required;
|
|
final bool nullable;
|
|
final dynamic example;
|
|
final dynamic defaultValue;
|
|
final String? reference;
|
|
final ApiModel? items; // 用于数组类型
|
|
|
|
const ApiProperty({
|
|
required this.name,
|
|
required this.type,
|
|
this.format,
|
|
required this.description,
|
|
required this.required,
|
|
this.nullable = false,
|
|
this.example,
|
|
this.defaultValue,
|
|
this.reference,
|
|
this.items,
|
|
});
|
|
|
|
/// 从JSON创建ApiProperty
|
|
factory ApiProperty.fromJson(
|
|
String name,
|
|
Map<String, dynamic> json,
|
|
List<String> requiredFields,
|
|
) {
|
|
final type = PropertyType.fromString(json['type'] as String? ?? 'string');
|
|
String? reference;
|
|
ApiModel? items;
|
|
|
|
// 处理引用类型
|
|
if (json['\$ref'] != null) {
|
|
final ref = json['\$ref'] as String;
|
|
reference = ref.split('/').last;
|
|
}
|
|
|
|
// 处理数组类型的 items
|
|
if (type == PropertyType.array && json['items'] != null) {
|
|
final itemsJson = json['items'] as Map<String, dynamic>;
|
|
|
|
// 如果 items 是引用类型
|
|
if (itemsJson['\$ref'] != null) {
|
|
final itemRef = itemsJson['\$ref'] as String;
|
|
final itemRefName = itemRef.split('/').last;
|
|
items = ApiModel(
|
|
name: itemRefName,
|
|
description: '',
|
|
properties: {},
|
|
required: [],
|
|
isEnum: false,
|
|
);
|
|
} else {
|
|
// 如果 items 是基本类型
|
|
final itemType =
|
|
PropertyType.fromString(itemsJson['type'] as String? ?? 'string');
|
|
items = ApiModel(
|
|
name: itemType.value,
|
|
description: '',
|
|
properties: {},
|
|
required: [],
|
|
isEnum: false,
|
|
);
|
|
}
|
|
}
|
|
|
|
return ApiProperty(
|
|
name: name,
|
|
type: reference != null ? PropertyType.reference : type,
|
|
format: json['format'] as String?,
|
|
description: json['description'] as String? ?? '',
|
|
required: requiredFields.contains(name),
|
|
nullable: json['nullable'] as bool? ?? false,
|
|
example: json['example'],
|
|
defaultValue: json['default'],
|
|
reference: reference,
|
|
items: items,
|
|
);
|
|
}
|
|
}
|
|
|
|
/// API控制器信息
|
|
class ApiController {
|
|
final String name;
|
|
final String description;
|
|
final List<ApiPath> paths;
|
|
|
|
const ApiController({
|
|
required this.name,
|
|
required this.description,
|
|
required this.paths,
|
|
});
|
|
|
|
/// 从路径列表创建ApiController
|
|
factory ApiController.fromPaths(String name, List<ApiPath> paths) {
|
|
return ApiController(name: name, description: name, paths: paths);
|
|
}
|
|
}
|