mirror of
https://github.com/foss42/apidash.git
synced 2025-12-01 18:28:25 +08:00
Merge branch 'main' into add-feat-insomia
This commit is contained in:
@@ -1,10 +1,12 @@
|
||||
import 'dart:convert';
|
||||
|
||||
enum APIType {
|
||||
rest("HTTP");
|
||||
rest("HTTP", "HTTP"),
|
||||
graphql("GraphQL", "GQL");
|
||||
|
||||
const APIType(this.label);
|
||||
const APIType(this.label, this.abbr);
|
||||
final String label;
|
||||
final String abbr;
|
||||
}
|
||||
|
||||
enum HTTPVerb {
|
||||
|
||||
@@ -19,3 +19,15 @@ extension StringExtension on String {
|
||||
return "${substring(0, limit)}...";
|
||||
}
|
||||
}
|
||||
|
||||
extension StringOrNullExtension on String? {
|
||||
bool isNullOrEmpty() {
|
||||
if (this == null) {
|
||||
return true;
|
||||
}
|
||||
if (this!.isEmpty) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,6 @@ import '../utils/utils.dart'
|
||||
import '../consts.dart';
|
||||
|
||||
part 'http_request_model.freezed.dart';
|
||||
|
||||
part 'http_request_model.g.dart';
|
||||
|
||||
@freezed
|
||||
@@ -27,6 +26,7 @@ class HttpRequestModel with _$HttpRequestModel {
|
||||
List<bool>? isParamEnabledList,
|
||||
@Default(ContentType.json) ContentType bodyContentType,
|
||||
String? body,
|
||||
String? query,
|
||||
List<FormDataModel>? formData,
|
||||
}) = _HttpRequestModel;
|
||||
|
||||
@@ -61,6 +61,7 @@ class HttpRequestModel with _$HttpRequestModel {
|
||||
kMethodsWithBody.contains(method) &&
|
||||
hasFormDataContentType &&
|
||||
formDataMapList.isNotEmpty;
|
||||
bool get hasQuery => query?.isNotEmpty ?? false;
|
||||
List<FormDataModel> get formDataList => formData ?? <FormDataModel>[];
|
||||
List<Map<String, String>> get formDataMapList =>
|
||||
rowsToFormDataMapList(formDataList) ?? [];
|
||||
|
||||
@@ -28,6 +28,7 @@ mixin _$HttpRequestModel {
|
||||
List<bool>? get isParamEnabledList => throw _privateConstructorUsedError;
|
||||
ContentType get bodyContentType => throw _privateConstructorUsedError;
|
||||
String? get body => throw _privateConstructorUsedError;
|
||||
String? get query => throw _privateConstructorUsedError;
|
||||
List<FormDataModel>? get formData => throw _privateConstructorUsedError;
|
||||
|
||||
/// Serializes this HttpRequestModel to a JSON map.
|
||||
@@ -55,6 +56,7 @@ abstract class $HttpRequestModelCopyWith<$Res> {
|
||||
List<bool>? isParamEnabledList,
|
||||
ContentType bodyContentType,
|
||||
String? body,
|
||||
String? query,
|
||||
List<FormDataModel>? formData});
|
||||
}
|
||||
|
||||
@@ -81,6 +83,7 @@ class _$HttpRequestModelCopyWithImpl<$Res, $Val extends HttpRequestModel>
|
||||
Object? isParamEnabledList = freezed,
|
||||
Object? bodyContentType = null,
|
||||
Object? body = freezed,
|
||||
Object? query = freezed,
|
||||
Object? formData = freezed,
|
||||
}) {
|
||||
return _then(_value.copyWith(
|
||||
@@ -116,6 +119,10 @@ class _$HttpRequestModelCopyWithImpl<$Res, $Val extends HttpRequestModel>
|
||||
? _value.body
|
||||
: body // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
query: freezed == query
|
||||
? _value.query
|
||||
: query // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
formData: freezed == formData
|
||||
? _value.formData
|
||||
: formData // ignore: cast_nullable_to_non_nullable
|
||||
@@ -141,6 +148,7 @@ abstract class _$$HttpRequestModelImplCopyWith<$Res>
|
||||
List<bool>? isParamEnabledList,
|
||||
ContentType bodyContentType,
|
||||
String? body,
|
||||
String? query,
|
||||
List<FormDataModel>? formData});
|
||||
}
|
||||
|
||||
@@ -165,6 +173,7 @@ class __$$HttpRequestModelImplCopyWithImpl<$Res>
|
||||
Object? isParamEnabledList = freezed,
|
||||
Object? bodyContentType = null,
|
||||
Object? body = freezed,
|
||||
Object? query = freezed,
|
||||
Object? formData = freezed,
|
||||
}) {
|
||||
return _then(_$HttpRequestModelImpl(
|
||||
@@ -200,6 +209,10 @@ class __$$HttpRequestModelImplCopyWithImpl<$Res>
|
||||
? _value.body
|
||||
: body // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
query: freezed == query
|
||||
? _value.query
|
||||
: query // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
formData: freezed == formData
|
||||
? _value._formData
|
||||
: formData // ignore: cast_nullable_to_non_nullable
|
||||
@@ -221,6 +234,7 @@ class _$HttpRequestModelImpl extends _HttpRequestModel {
|
||||
final List<bool>? isParamEnabledList,
|
||||
this.bodyContentType = ContentType.json,
|
||||
this.body,
|
||||
this.query,
|
||||
final List<FormDataModel>? formData})
|
||||
: _headers = headers,
|
||||
_params = params,
|
||||
@@ -285,6 +299,8 @@ class _$HttpRequestModelImpl extends _HttpRequestModel {
|
||||
final ContentType bodyContentType;
|
||||
@override
|
||||
final String? body;
|
||||
@override
|
||||
final String? query;
|
||||
final List<FormDataModel>? _formData;
|
||||
@override
|
||||
List<FormDataModel>? get formData {
|
||||
@@ -297,7 +313,7 @@ class _$HttpRequestModelImpl extends _HttpRequestModel {
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'HttpRequestModel(method: $method, url: $url, headers: $headers, params: $params, isHeaderEnabledList: $isHeaderEnabledList, isParamEnabledList: $isParamEnabledList, bodyContentType: $bodyContentType, body: $body, formData: $formData)';
|
||||
return 'HttpRequestModel(method: $method, url: $url, headers: $headers, params: $params, isHeaderEnabledList: $isHeaderEnabledList, isParamEnabledList: $isParamEnabledList, bodyContentType: $bodyContentType, body: $body, query: $query, formData: $formData)';
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -316,6 +332,7 @@ class _$HttpRequestModelImpl extends _HttpRequestModel {
|
||||
(identical(other.bodyContentType, bodyContentType) ||
|
||||
other.bodyContentType == bodyContentType) &&
|
||||
(identical(other.body, body) || other.body == body) &&
|
||||
(identical(other.query, query) || other.query == query) &&
|
||||
const DeepCollectionEquality().equals(other._formData, _formData));
|
||||
}
|
||||
|
||||
@@ -331,6 +348,7 @@ class _$HttpRequestModelImpl extends _HttpRequestModel {
|
||||
const DeepCollectionEquality().hash(_isParamEnabledList),
|
||||
bodyContentType,
|
||||
body,
|
||||
query,
|
||||
const DeepCollectionEquality().hash(_formData));
|
||||
|
||||
/// Create a copy of HttpRequestModel
|
||||
@@ -360,6 +378,7 @@ abstract class _HttpRequestModel extends HttpRequestModel {
|
||||
final List<bool>? isParamEnabledList,
|
||||
final ContentType bodyContentType,
|
||||
final String? body,
|
||||
final String? query,
|
||||
final List<FormDataModel>? formData}) = _$HttpRequestModelImpl;
|
||||
const _HttpRequestModel._() : super._();
|
||||
|
||||
@@ -383,6 +402,8 @@ abstract class _HttpRequestModel extends HttpRequestModel {
|
||||
@override
|
||||
String? get body;
|
||||
@override
|
||||
String? get query;
|
||||
@override
|
||||
List<FormDataModel>? get formData;
|
||||
|
||||
/// Create a copy of HttpRequestModel
|
||||
|
||||
@@ -29,6 +29,7 @@ _$HttpRequestModelImpl _$$HttpRequestModelImplFromJson(Map json) =>
|
||||
$enumDecodeNullable(_$ContentTypeEnumMap, json['bodyContentType']) ??
|
||||
ContentType.json,
|
||||
body: json['body'] as String?,
|
||||
query: json['query'] as String?,
|
||||
formData: (json['formData'] as List<dynamic>?)
|
||||
?.map((e) =>
|
||||
FormDataModel.fromJson(Map<String, Object?>.from(e as Map)))
|
||||
@@ -46,6 +47,7 @@ Map<String, dynamic> _$$HttpRequestModelImplToJson(
|
||||
'isParamEnabledList': instance.isParamEnabledList,
|
||||
'bodyContentType': _$ContentTypeEnumMap[instance.bodyContentType]!,
|
||||
'body': instance.body,
|
||||
'query': instance.query,
|
||||
'formData': instance.formData?.map((e) => e.toJson()).toList(),
|
||||
};
|
||||
|
||||
|
||||
@@ -10,7 +10,6 @@ import '../utils/utils.dart';
|
||||
import '../consts.dart';
|
||||
|
||||
part 'http_response_model.freezed.dart';
|
||||
|
||||
part 'http_response_model.g.dart';
|
||||
|
||||
class Uint8ListConverter implements JsonConverter<Uint8List?, List<int>?> {
|
||||
|
||||
@@ -12,6 +12,7 @@ typedef HttpResponse = http.Response;
|
||||
|
||||
Future<(HttpResponse?, Duration?, String?)> request(
|
||||
String requestId,
|
||||
APIType apiType,
|
||||
HttpRequestModel requestModel, {
|
||||
SupportedUriSchemes defaultUriScheme = kDefaultUriScheme,
|
||||
bool noSSL = false,
|
||||
@@ -28,74 +29,96 @@ Future<(HttpResponse?, Duration?, String?)> request(
|
||||
if (uriRec.$1 != null) {
|
||||
Uri requestUrl = uriRec.$1!;
|
||||
Map<String, String> headers = requestModel.enabledHeadersMap;
|
||||
HttpResponse response;
|
||||
HttpResponse? response;
|
||||
String? body;
|
||||
try {
|
||||
Stopwatch stopwatch = Stopwatch()..start();
|
||||
var isMultiPartRequest =
|
||||
requestModel.bodyContentType == ContentType.formdata;
|
||||
if (apiType == APIType.rest) {
|
||||
var isMultiPartRequest =
|
||||
requestModel.bodyContentType == ContentType.formdata;
|
||||
|
||||
if (kMethodsWithBody.contains(requestModel.method)) {
|
||||
var requestBody = requestModel.body;
|
||||
if (requestBody != null && !isMultiPartRequest) {
|
||||
if (kMethodsWithBody.contains(requestModel.method)) {
|
||||
var requestBody = requestModel.body;
|
||||
if (requestBody != null && !isMultiPartRequest) {
|
||||
var contentLength = utf8.encode(requestBody).length;
|
||||
if (contentLength > 0) {
|
||||
body = requestBody;
|
||||
headers[HttpHeaders.contentLengthHeader] =
|
||||
contentLength.toString();
|
||||
if (!requestModel.hasContentTypeHeader) {
|
||||
headers[HttpHeaders.contentTypeHeader] =
|
||||
requestModel.bodyContentType.header;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (isMultiPartRequest) {
|
||||
var multiPartRequest = http.MultipartRequest(
|
||||
requestModel.method.name.toUpperCase(),
|
||||
requestUrl,
|
||||
);
|
||||
multiPartRequest.headers.addAll(headers);
|
||||
for (var formData in requestModel.formDataList) {
|
||||
if (formData.type == FormDataType.text) {
|
||||
multiPartRequest.fields.addAll({formData.name: formData.value});
|
||||
} else {
|
||||
multiPartRequest.files.add(
|
||||
await http.MultipartFile.fromPath(
|
||||
formData.name,
|
||||
formData.value,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
http.StreamedResponse multiPartResponse =
|
||||
await multiPartRequest.send();
|
||||
stopwatch.stop();
|
||||
http.Response convertedMultiPartResponse =
|
||||
await convertStreamedResponse(multiPartResponse);
|
||||
return (convertedMultiPartResponse, stopwatch.elapsed, null);
|
||||
}
|
||||
}
|
||||
switch (requestModel.method) {
|
||||
case HTTPVerb.get:
|
||||
response = await client.get(requestUrl, headers: headers);
|
||||
break;
|
||||
case HTTPVerb.head:
|
||||
response = await client.head(requestUrl, headers: headers);
|
||||
break;
|
||||
case HTTPVerb.post:
|
||||
response =
|
||||
await client.post(requestUrl, headers: headers, body: body);
|
||||
break;
|
||||
case HTTPVerb.put:
|
||||
response =
|
||||
await client.put(requestUrl, headers: headers, body: body);
|
||||
break;
|
||||
case HTTPVerb.patch:
|
||||
response =
|
||||
await client.patch(requestUrl, headers: headers, body: body);
|
||||
break;
|
||||
case HTTPVerb.delete:
|
||||
response =
|
||||
await client.delete(requestUrl, headers: headers, body: body);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (apiType == APIType.graphql) {
|
||||
var requestBody = getGraphQLBody(requestModel);
|
||||
if (requestBody != null) {
|
||||
var contentLength = utf8.encode(requestBody).length;
|
||||
if (contentLength > 0) {
|
||||
body = requestBody;
|
||||
headers[HttpHeaders.contentLengthHeader] = contentLength.toString();
|
||||
if (!requestModel.hasContentTypeHeader) {
|
||||
headers[HttpHeaders.contentTypeHeader] =
|
||||
requestModel.bodyContentType.header;
|
||||
headers[HttpHeaders.contentTypeHeader] = ContentType.json.header;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (isMultiPartRequest) {
|
||||
var multiPartRequest = http.MultipartRequest(
|
||||
requestModel.method.name.toUpperCase(),
|
||||
requestUrl,
|
||||
);
|
||||
multiPartRequest.headers.addAll(headers);
|
||||
for (var formData in requestModel.formDataList) {
|
||||
if (formData.type == FormDataType.text) {
|
||||
multiPartRequest.fields.addAll({formData.name: formData.value});
|
||||
} else {
|
||||
multiPartRequest.files.add(
|
||||
await http.MultipartFile.fromPath(
|
||||
formData.name,
|
||||
formData.value,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
http.StreamedResponse multiPartResponse =
|
||||
await multiPartRequest.send();
|
||||
stopwatch.stop();
|
||||
http.Response convertedMultiPartResponse =
|
||||
await convertStreamedResponse(multiPartResponse);
|
||||
return (convertedMultiPartResponse, stopwatch.elapsed, null);
|
||||
}
|
||||
}
|
||||
switch (requestModel.method) {
|
||||
case HTTPVerb.get:
|
||||
response = await client.get(requestUrl, headers: headers);
|
||||
break;
|
||||
case HTTPVerb.head:
|
||||
response = await client.head(requestUrl, headers: headers);
|
||||
break;
|
||||
case HTTPVerb.post:
|
||||
response =
|
||||
await client.post(requestUrl, headers: headers, body: body);
|
||||
break;
|
||||
case HTTPVerb.put:
|
||||
response = await client.put(requestUrl, headers: headers, body: body);
|
||||
break;
|
||||
case HTTPVerb.patch:
|
||||
response =
|
||||
await client.patch(requestUrl, headers: headers, body: body);
|
||||
break;
|
||||
case HTTPVerb.delete:
|
||||
response =
|
||||
await client.delete(requestUrl, headers: headers, body: body);
|
||||
break;
|
||||
response = await client.post(
|
||||
requestUrl,
|
||||
headers: headers,
|
||||
body: body,
|
||||
);
|
||||
}
|
||||
stopwatch.stop();
|
||||
return (response, stopwatch.elapsed, null);
|
||||
|
||||
11
packages/apidash_core/lib/utils/graphql_utils.dart
Normal file
11
packages/apidash_core/lib/utils/graphql_utils.dart
Normal file
@@ -0,0 +1,11 @@
|
||||
import '../consts.dart';
|
||||
import '../models/models.dart';
|
||||
|
||||
String? getGraphQLBody(HttpRequestModel httpRequestModel) {
|
||||
if (httpRequestModel.hasQuery) {
|
||||
return kJsonEncoder.convert({
|
||||
"query": httpRequestModel.query,
|
||||
});
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -1,5 +1,8 @@
|
||||
import 'package:apidash_core/consts.dart';
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:seed/seed.dart';
|
||||
import '../models/models.dart';
|
||||
import 'graphql_utils.dart';
|
||||
|
||||
Map<String, String>? rowsToMap(
|
||||
List<NameValueModel>? kvRows, {
|
||||
@@ -88,3 +91,13 @@ List<NameValueModel>? getEnabledRows(
|
||||
rows.where((element) => isRowEnabledList[rows.indexOf(element)]).toList();
|
||||
return finalRows == [] ? null : finalRows;
|
||||
}
|
||||
|
||||
String? getRequestBody(APIType type, HttpRequestModel httpRequestModel) {
|
||||
return switch (type) {
|
||||
APIType.rest =>
|
||||
(httpRequestModel.hasJsonData || httpRequestModel.hasTextData)
|
||||
? httpRequestModel.body
|
||||
: null,
|
||||
APIType.graphql => getGraphQLBody(httpRequestModel),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
export 'content_type_utils.dart';
|
||||
export 'graphql_utils.dart';
|
||||
export 'http_request_utils.dart';
|
||||
export 'http_response_utils.dart';
|
||||
export 'string_utils.dart';
|
||||
|
||||
@@ -21,7 +21,7 @@ dependencies:
|
||||
path: ../postman
|
||||
insomnia_collection:
|
||||
path: ../insomnia_collection
|
||||
seed: ^0.0.2
|
||||
seed: ^0.0.3
|
||||
xml: ^6.3.0
|
||||
|
||||
dev_dependencies:
|
||||
@@ -30,4 +30,5 @@ dev_dependencies:
|
||||
build_runner: ^2.4.12
|
||||
flutter_lints: ^4.0.0
|
||||
freezed: ^2.5.7
|
||||
json_serializable: ^6.7.1
|
||||
test: ^1.25.2
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
# melos_managed_dependency_overrides: seed,curl_parser
|
||||
# melos_managed_dependency_overrides: curl_parser,postman,seed
|
||||
dependency_overrides:
|
||||
curl_parser:
|
||||
path: ../curl_parser
|
||||
postman:
|
||||
path: ../postman
|
||||
seed:
|
||||
path: ../seed
|
||||
|
||||
Reference in New Issue
Block a user