mirror of
https://github.com/foss42/apidash.git
synced 2025-06-01 23:45:19 +08:00
Adding http services along with provider + model modifications
This commit is contained in:
@ -1,4 +1,8 @@
|
|||||||
|
import 'dart:io';
|
||||||
|
import 'dart:convert';
|
||||||
|
import 'package:collection/collection.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:http/http.dart';
|
||||||
import 'kvrow_model.dart';
|
import 'kvrow_model.dart';
|
||||||
import '../consts.dart';
|
import '../consts.dart';
|
||||||
|
|
||||||
@ -13,6 +17,9 @@ class RequestModel {
|
|||||||
this.requestParams,
|
this.requestParams,
|
||||||
this.requestBodyContentType = DEFAULT_BODY_CONTENT_TYPE,
|
this.requestBodyContentType = DEFAULT_BODY_CONTENT_TYPE,
|
||||||
this.requestBody,
|
this.requestBody,
|
||||||
|
this.responseStatus,
|
||||||
|
this.message,
|
||||||
|
this.responseModel,
|
||||||
});
|
});
|
||||||
|
|
||||||
final String id;
|
final String id;
|
||||||
@ -23,6 +30,9 @@ class RequestModel {
|
|||||||
final List<KVRow>? requestParams;
|
final List<KVRow>? requestParams;
|
||||||
final ContentType requestBodyContentType;
|
final ContentType requestBodyContentType;
|
||||||
final dynamic requestBody;
|
final dynamic requestBody;
|
||||||
|
final int? responseStatus;
|
||||||
|
final String? message;
|
||||||
|
final ResponseModel? responseModel;
|
||||||
|
|
||||||
RequestModel duplicate({
|
RequestModel duplicate({
|
||||||
required String id,
|
required String id,
|
||||||
@ -47,6 +57,9 @@ class RequestModel {
|
|||||||
List<KVRow>? requestParams,
|
List<KVRow>? requestParams,
|
||||||
ContentType? requestBodyContentType,
|
ContentType? requestBodyContentType,
|
||||||
dynamic requestBody,
|
dynamic requestBody,
|
||||||
|
int? responseStatus,
|
||||||
|
String? message,
|
||||||
|
ResponseModel? responseModel,
|
||||||
}) {
|
}) {
|
||||||
return RequestModel(
|
return RequestModel(
|
||||||
id: id ?? this.id,
|
id: id ?? this.id,
|
||||||
@ -58,6 +71,9 @@ class RequestModel {
|
|||||||
requestBodyContentType:
|
requestBodyContentType:
|
||||||
requestBodyContentType ?? this.requestBodyContentType,
|
requestBodyContentType ?? this.requestBodyContentType,
|
||||||
requestBody: requestBody ?? this.requestBody,
|
requestBody: requestBody ?? this.requestBody,
|
||||||
|
responseStatus: responseStatus ?? this.responseStatus,
|
||||||
|
message: message ?? this.message,
|
||||||
|
responseModel: responseModel ?? this.responseModel,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -72,6 +88,59 @@ class RequestModel {
|
|||||||
"Request Params: ${requestParams.toString()}",
|
"Request Params: ${requestParams.toString()}",
|
||||||
"Request Body Content Type: ${requestBodyContentType.toString()}",
|
"Request Body Content Type: ${requestBodyContentType.toString()}",
|
||||||
"Request Body: ${requestBody.toString()}",
|
"Request Body: ${requestBody.toString()}",
|
||||||
|
"Response Status: $responseStatus",
|
||||||
|
"Response Message: $message",
|
||||||
|
"Response: ${responseModel.toString()}"
|
||||||
|
].join("\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@immutable
|
||||||
|
class ResponseModel {
|
||||||
|
const ResponseModel({
|
||||||
|
this.statusCode,
|
||||||
|
this.headers,
|
||||||
|
this.requestHeaders,
|
||||||
|
this.contentType,
|
||||||
|
this.body,
|
||||||
|
this.time,
|
||||||
|
});
|
||||||
|
|
||||||
|
final int? statusCode;
|
||||||
|
final Map<String, String>? headers;
|
||||||
|
final Map<String, String>? requestHeaders;
|
||||||
|
final String? contentType;
|
||||||
|
final String? body;
|
||||||
|
final Duration? time;
|
||||||
|
|
||||||
|
ResponseModel fromResponse({
|
||||||
|
required Response response,
|
||||||
|
Duration? time,
|
||||||
|
}) {
|
||||||
|
var contentType = response.headers[HttpHeaders.contentTypeHeader];
|
||||||
|
final responseHeaders = mergeMaps(
|
||||||
|
{HttpHeaders.contentLengthHeader: response.contentLength.toString()},
|
||||||
|
response.headers);
|
||||||
|
return ResponseModel(
|
||||||
|
statusCode: response.statusCode,
|
||||||
|
headers: responseHeaders,
|
||||||
|
requestHeaders: response.request?.headers,
|
||||||
|
contentType: contentType,
|
||||||
|
body: contentType == JSON_MIMETYPE
|
||||||
|
? utf8.decode(response.bodyBytes)
|
||||||
|
: response.body,
|
||||||
|
time: time,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return [
|
||||||
|
"Response Status: $statusCode",
|
||||||
|
"Response Time: $time",
|
||||||
|
"Response Headers: ${headers.toString()}",
|
||||||
|
"Response Request Headers: ${requestHeaders.toString()}",
|
||||||
|
"Response Body: $body",
|
||||||
].join("\n");
|
].join("\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
import 'package:uuid/uuid.dart';
|
import 'package:uuid/uuid.dart';
|
||||||
import '../models/models.dart';
|
import '../models/models.dart';
|
||||||
|
import '../services/services.dart';
|
||||||
import '../consts.dart';
|
import '../consts.dart';
|
||||||
|
|
||||||
const _uuid = Uuid();
|
const _uuid = Uuid();
|
||||||
@ -63,20 +64,51 @@ class CollectionStateNotifier extends StateNotifier<List<RequestModel>> {
|
|||||||
List<KVRow>? requestParams,
|
List<KVRow>? requestParams,
|
||||||
ContentType? requestBodyContentType,
|
ContentType? requestBodyContentType,
|
||||||
dynamic requestBody,
|
dynamic requestBody,
|
||||||
|
int? responseStatus,
|
||||||
|
String? message,
|
||||||
|
ResponseModel? responseModel,
|
||||||
}) {
|
}) {
|
||||||
final idx = idxOfId(id);
|
final idx = idxOfId(id);
|
||||||
final newModel = state[idx].copyWith(
|
final newModel = state[idx].copyWith(
|
||||||
method: method,
|
method: method,
|
||||||
url: url,
|
url: url,
|
||||||
requestTabIndex: requestTabIndex,
|
requestTabIndex: requestTabIndex,
|
||||||
requestHeaders: requestHeaders,
|
requestHeaders: requestHeaders,
|
||||||
requestParams: requestParams,
|
requestParams: requestParams,
|
||||||
requestBodyContentType: requestBodyContentType,
|
requestBodyContentType: requestBodyContentType,
|
||||||
requestBody: requestBody,
|
requestBody: requestBody,
|
||||||
);
|
responseStatus: responseStatus,
|
||||||
|
message: message,
|
||||||
|
responseModel: responseModel);
|
||||||
//print(newModel);
|
//print(newModel);
|
||||||
state = [...state.sublist(0, idx), newModel, ...state.sublist(idx + 1)];
|
state = [...state.sublist(0, idx), newModel, ...state.sublist(idx + 1)];
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> sendRequest(String id) async {}
|
Future<void> sendRequest(String id) async {
|
||||||
|
final idx = idxOfId(id);
|
||||||
|
RequestModel requestModel = getRequestModel(id);
|
||||||
|
var responseRec = await request(requestModel);
|
||||||
|
late final RequestModel newRequestModel;
|
||||||
|
if (responseRec.$0 == null) {
|
||||||
|
newRequestModel = requestModel.copyWith(
|
||||||
|
responseStatus: -1,
|
||||||
|
message: responseRec.$2,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
final responseModel = ResponseModel()
|
||||||
|
.fromResponse(response: responseRec.$0!, time: responseRec.$1!);
|
||||||
|
int statusCode = responseRec.$0!.statusCode;
|
||||||
|
newRequestModel = requestModel.copyWith(
|
||||||
|
responseStatus: statusCode,
|
||||||
|
message: RESPONSE_CODE_REASONS[statusCode],
|
||||||
|
responseModel: responseModel,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
print(newRequestModel);
|
||||||
|
state = [
|
||||||
|
...state.sublist(0, idx),
|
||||||
|
newRequestModel,
|
||||||
|
...state.sublist(idx + 1)
|
||||||
|
];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
130
lib/services/http_service.dart
Normal file
130
lib/services/http_service.dart
Normal file
@ -0,0 +1,130 @@
|
|||||||
|
import 'dart:async';
|
||||||
|
import 'dart:convert';
|
||||||
|
import 'dart:io';
|
||||||
|
import 'package:flutter_api_tool/consts.dart';
|
||||||
|
import 'package:http/http.dart' as http;
|
||||||
|
import 'package:collection/collection.dart' show mergeMaps;
|
||||||
|
import '../models/models.dart';
|
||||||
|
|
||||||
|
const SUPPORTED_URI_SCHEMES = [
|
||||||
|
"https",
|
||||||
|
"http"
|
||||||
|
];
|
||||||
|
|
||||||
|
const DEFAULT_URI_SCHEME = "https://";
|
||||||
|
|
||||||
|
const METHODS_WITH_BODY = [HTTPVerb.post, HTTPVerb.put, HTTPVerb.patch, HTTPVerb.delete,];
|
||||||
|
|
||||||
|
(String?, bool) getUriScheme(Uri uri) {
|
||||||
|
if(uri.hasScheme){
|
||||||
|
if(SUPPORTED_URI_SCHEMES.contains(uri.scheme)){
|
||||||
|
return (uri.scheme, true);
|
||||||
|
}
|
||||||
|
return (uri.scheme, false);
|
||||||
|
}
|
||||||
|
return (null, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
(Uri?, String?) getValidRequestUri(String? url, List<KVRow>? requestParams) {
|
||||||
|
if(url == null || url.trim() == ""){
|
||||||
|
return (null, "URL is missing!");
|
||||||
|
}
|
||||||
|
Uri? uri = Uri.tryParse(url);
|
||||||
|
if(uri == null){
|
||||||
|
return (null, "Check URL (malformed)");
|
||||||
|
}
|
||||||
|
(String?, bool) urlScheme = getUriScheme(uri);
|
||||||
|
|
||||||
|
if(urlScheme.$0 != null){
|
||||||
|
if (!urlScheme.$1){
|
||||||
|
return (null, "Unsupported URL Scheme (${urlScheme.$0})");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
url = DEFAULT_URI_SCHEME + url;
|
||||||
|
}
|
||||||
|
|
||||||
|
uri = Uri.parse(url);
|
||||||
|
if (uri.hasFragment){
|
||||||
|
uri = uri.removeFragment();
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, String>? queryParams = rowsToMap(requestParams);
|
||||||
|
if(queryParams != null){
|
||||||
|
if(uri.hasQuery){
|
||||||
|
Map<String, String> urlQueryParams = uri.queryParameters;
|
||||||
|
queryParams = mergeMaps(urlQueryParams, queryParams);
|
||||||
|
}
|
||||||
|
uri = uri.replace(queryParameters: queryParams);
|
||||||
|
}
|
||||||
|
return (uri, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<(http.Response?, Duration?, String?)> request(RequestModel requestModel) async {
|
||||||
|
(Uri?, String?) uriRec = getValidRequestUri(requestModel.url,
|
||||||
|
requestModel.requestParams);
|
||||||
|
if(uriRec.$0 != null){
|
||||||
|
Uri requestUrl = uriRec.$0!;
|
||||||
|
Map<String, String> headers = rowsToMap(requestModel.requestHeaders) ?? {};
|
||||||
|
http.Response response;
|
||||||
|
String? body;
|
||||||
|
try {
|
||||||
|
if(METHODS_WITH_BODY.contains(requestModel.method)){
|
||||||
|
if(requestModel.requestBody != null){
|
||||||
|
var contentLength = utf8.encode(requestModel.requestBody).length;
|
||||||
|
if (contentLength > 0){
|
||||||
|
body = requestModel.requestBody as String;
|
||||||
|
headers[HttpHeaders.contentLengthHeader] = contentLength.toString();
|
||||||
|
switch(requestModel.requestBodyContentType){
|
||||||
|
case ContentType.json:
|
||||||
|
headers[HttpHeaders.contentTypeHeader] = 'application/json';
|
||||||
|
break;
|
||||||
|
case ContentType.text:
|
||||||
|
headers[HttpHeaders.contentTypeHeader] = 'text/plain';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Stopwatch stopwatch = Stopwatch()..start();
|
||||||
|
switch(requestModel.method){
|
||||||
|
case HTTPVerb.get:
|
||||||
|
response = await http.get(requestUrl,
|
||||||
|
headers: headers);
|
||||||
|
break;
|
||||||
|
case HTTPVerb.head:
|
||||||
|
response = await http.head(requestUrl,
|
||||||
|
headers: headers);
|
||||||
|
break;
|
||||||
|
case HTTPVerb.post:
|
||||||
|
response = await http.post(requestUrl,
|
||||||
|
headers: headers,
|
||||||
|
body: body);
|
||||||
|
break;
|
||||||
|
case HTTPVerb.put:
|
||||||
|
response = await http.put(requestUrl,
|
||||||
|
headers: headers,
|
||||||
|
body: body);
|
||||||
|
break;
|
||||||
|
case HTTPVerb.patch:
|
||||||
|
response = await http.patch(requestUrl,
|
||||||
|
headers: headers,
|
||||||
|
body: body);
|
||||||
|
break;
|
||||||
|
case HTTPVerb.delete:
|
||||||
|
response = await http.delete(requestUrl,
|
||||||
|
headers: headers,
|
||||||
|
body: body);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
stopwatch.stop();
|
||||||
|
return (response, stopwatch.elapsed, null);
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
return (null, null, e.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return (null, null, uriRec.$1);
|
||||||
|
}
|
||||||
|
}
|
1
lib/services/services.dart
Normal file
1
lib/services/services.dart
Normal file
@ -0,0 +1 @@
|
|||||||
|
export 'http_service.dart';
|
@ -15,6 +15,8 @@ dependencies:
|
|||||||
uuid: ^3.0.7
|
uuid: ^3.0.7
|
||||||
tab_container: ^2.0.0
|
tab_container: ^2.0.0
|
||||||
davi: ^3.2.0
|
davi: ^3.2.0
|
||||||
|
http: ^0.13.5
|
||||||
|
collection: ^1.17.0
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
|
Reference in New Issue
Block a user