diff --git a/lib/codegen/csharp/http_client.dart b/lib/codegen/csharp/http_client.dart index 6d086db83..370638163 100644 --- a/lib/codegen/csharp/http_client.dart +++ b/lib/codegen/csharp/http_client.dart @@ -5,19 +5,32 @@ class CSharpHttpClientCodeGen { final String kTemplateNamespaces = r''' using System; using System.Net.Http; +using System.Collections.Generic; +using System.Linq; {%- if formdata == 'multipart' %} using System.IO; -{%- elif formdata == 'urlencoded' %} -using System.Collections.Generic; {%- endif %} '''; - final String kTemplateUri = ''' -string uri = "{{ uri }}"; +final String kTemplateQueryParams = ''' +string baseUri = "{{ baseUri }}"; + +var query = new Dictionary>(); +{%- for key, values in queryParams %} + query["{{ key }}"] = new List(); + {%- for value in values %} + query["{{ key }}"].Add("{{ value }}"); + {%- endfor %} +{%- endfor %} + +var queryString = string.Join("&", query.SelectMany(kv => kv.Value.Select(v => string.Format("{0}={1}", kv.Key, v)))); +string uri = string.Format("{0}?{1}", baseUri, queryString); '''; + + final String kTemplateHttpClientAndRequest = ''' using (var client = new HttpClient()) using (var request = new HttpRequestMessage(HttpMethod.{{ method | capitalize }}, uri)) @@ -81,17 +94,23 @@ using (var request = new HttpRequestMessage(HttpMethod.{{ method | capitalize }} StringBuffer result = StringBuffer(); // Include necessary C# namespace - String formdataImport = requestModel.hasFormData - ? "multipart" //(requestModel.hasFileInFormData ? "multipart" : "urlencoded") - : "nodata"; + String formdataImport = requestModel.hasFormData + ? "multipart" //(requestModel.hasFileInFormData ? "multipart" : "urlencoded") + : "nodata"; result.writeln(jj.Template(kTemplateNamespaces) - .render({"formdata": formdataImport})); - - // Set request URL - var (uri, _) = - getValidRequestUri(requestModel.url, requestModel.enabledParams); - if (uri != null) { - result.writeln(jj.Template(kTemplateUri).render({"uri": uri})); + .render({"formdata": formdataImport})); + + // Extract query parameters and URL + String baseUri = requestModel.url.split('?')[0]; + var queryParams = requestModel.enabledParamsMap; + + if (queryParams.isNotEmpty) { + result.writeln(jj.Template(kTemplateQueryParams).render({ + "baseUri": baseUri, + "queryParams": queryParams, + })); + } else { + result.writeln('string uri = "$baseUri";\n'); } // Initialize HttpClient and create HttpRequestMessage @@ -103,18 +122,18 @@ using (var request = new HttpRequestMessage(HttpMethod.{{ method | capitalize }} var headers = requestModel.enabledHeadersMap; if (headers.isNotEmpty) { result.writeln( - jj.Template(kTemplateHeaders).render({"headers": headers})); + jj.Template(kTemplateHeaders).render({"headers": headers})); } // Set request body if exists if (kMethodsWithBody.contains(requestModel.method) && - requestModel.hasBody) { + requestModel.hasBody) { var requestBody = requestModel.body; if (!requestModel.hasFormData && - requestBody != null && - requestBody.isNotEmpty) { - // if the request body is not formdata then render raw text body + requestBody != null && + requestBody.isNotEmpty) { + // if the request body is not formdata then render raw text body result.writeln(jj.Template(kTemplateRawBody).render({ "body": requestBody, "mediaType": requestModel.bodyContentType.header, @@ -133,7 +152,7 @@ using (var request = new HttpRequestMessage(HttpMethod.{{ method | capitalize }} result.writeln(kStringContentSetup); } - // Send request and get response + // Send request and get response result.write(kStringEnd); return result.toString(); } catch (e) { diff --git a/lib/codegen/csharp/rest_sharp.dart b/lib/codegen/csharp/rest_sharp.dart index efebb7cf9..0d0747d0d 100644 --- a/lib/codegen/csharp/rest_sharp.dart +++ b/lib/codegen/csharp/rest_sharp.dart @@ -113,19 +113,20 @@ class Program }); result += methodType; - if (uri.hasQuery) { - var params = uri.queryParameters; - if (params.isNotEmpty) { - jj.Template templateParams = jj.Template(kTemplateParams); - String paramsResult = ""; - for (var item in params.entries) { - paramsResult += templateParams - .render({"param": item.key, "value": item.value}); + if (requestModel.enabledParamsMap.isNotEmpty) { + jj.Template templateParams = jj.Template(kTemplateParams); + String paramsResult = ""; + + requestModel.enabledParamsMap.forEach((key, values) { + for (var value in values) { + paramsResult += templateParams.render({"param": key, "value": value}); } - result += "$paramsResult\n"; - } + }); + + result += "$paramsResult\n"; } + var headersList = requestModel.enabledHeaders; if (headersList != null || requestModel.hasJsonData || diff --git a/lib/codegen/dart/dio.dart b/lib/codegen/dart/dio.dart index 488d3cc7f..5ade085fd 100644 --- a/lib/codegen/dart/dio.dart +++ b/lib/codegen/dart/dio.dart @@ -28,7 +28,7 @@ class DartDioCodeGen { String generatedDartCode({ required String url, required HTTPVerb method, - required Map queryParams, + required Map queryParams, required Map headers, required String? body, required ContentType contentType, @@ -87,11 +87,12 @@ class DartDioCodeGen { dataExp = declareFinal('data').assign(refer('dio.FormData()')); } } + final parsedUrl = url.split('?').first; final responseExp = declareFinal('response').assign(InvokeExpression.newOf( refer('dio.Dio()'), - [literalString(url)], + [literalString(parsedUrl)], { - if (queryParamExp != null) 'queryParameters': refer('queryParams'), + if (queryParamExp != null) 'queryParameters': refer('queryParams'), if (headerExp != null) 'options': refer('dio.Options').newInstance( [], diff --git a/lib/codegen/dart/http.dart b/lib/codegen/dart/http.dart index 2c7e66a54..a6a6a0061 100644 --- a/lib/codegen/dart/http.dart +++ b/lib/codegen/dart/http.dart @@ -30,7 +30,7 @@ class DartHttpCodeGen { String generatedDartCode({ required String url, required HTTPVerb method, - required Map queryParams, + required Map queryParams, required Map headers, required ContentType contentType, required String? body, @@ -43,9 +43,9 @@ class DartHttpCodeGen { final emitter = DartEmitter(); final dioImport = Directive.import('package:http/http.dart', as: 'http'); sbf.writeln(dioImport.accept(emitter)); - + final parsedUrl = url.split('?').first; final uriExp = - declareVar('uri').assign(refer('Uri.parse').call([literalString(url)])); + declareVar('uri').assign(refer('Uri.parse').call([literalString(parsedUrl)])); Expression? dataExp; if (kMethodsWithBody.contains(method) && @@ -61,7 +61,7 @@ class DartHttpCodeGen { Expression? queryParamExp; List? uriReassignExps; - // var urlQueryParams = Map.from(uri.queryParameters); + // var urlQueryParams = Map.from(uri.queryParameters); // urlQueryParams.addAll(queryParams); // uri = uri.replace(queryParameters: urlQueryParams); @@ -74,7 +74,7 @@ class DartHttpCodeGen { if (uri.hasQuery) declareVar('urlQueryParams').assign( InvokeExpression.newOf( - refer('Map'), + refer('Map'), [refer('uri.queryParameters')], {}, [], diff --git a/lib/codegen/go/http.dart b/lib/codegen/go/http.dart index 28fd805a2..36b958c93 100644 --- a/lib/codegen/go/http.dart +++ b/lib/codegen/go/http.dart @@ -58,14 +58,15 @@ func main() { """; String kTemplateQueryParam = """ - query := url.Query() - {% for key, value in params %} - query.Set("{{key}}", "{{value}}"){% endfor %} +query := url.Query() +{% for param in params %} +query.Add("{{param.key}}", "{{param.value}}"){% endfor %} - url.RawQuery = query.Encode() +url.RawQuery = query.Encode() """; + String kTemplateRequest = """ req, _ := http.NewRequest("{{method}}", url.String(), {% if hasBody %}payload{% else %}nil{% endif %}) @@ -102,7 +103,7 @@ func main() { }); var templateUrl = jj.Template(kTemplateUrl); - result += templateUrl.render({"url": url}); + result += templateUrl.render({"url": url.split('?').first}); var rec = getValidRequestUri( url, @@ -124,15 +125,17 @@ func main() { "fields": requestModel.formDataMapList, }); } - - if (uri.hasQuery) { - var params = uri.queryParameters; - if (params.isNotEmpty) { - var templateQueryParam = jj.Template(kTemplateQueryParam); - result += templateQueryParam.render({"params": params}); - } + if (requestModel.enabledParamsMap.isNotEmpty) { + var queryParams = []; + requestModel.enabledParamsMap.forEach((key, value) { + for (var v in value) { + queryParams.add({'key': key, 'value': v}); } + }); + var templateQueryParam = jj.Template(kTemplateQueryParam); + result += templateQueryParam.render({"params": queryParams}); + } var method = requestModel.method.name.toUpperCase(); var templateRequest = jj.Template(kTemplateRequest); result += templateRequest.render({ diff --git a/lib/codegen/java/async_http_client.dart b/lib/codegen/java/async_http_client.dart index 4b1957389..e4060995e 100644 --- a/lib/codegen/java/async_http_client.dart +++ b/lib/codegen/java/async_http_client.dart @@ -36,14 +36,13 @@ public class Main { '''; final String kTemplateRequestCreation = ''' - BoundRequestBuilder requestBuilder = asyncHttpClient.prepare("{{ method|upper }}", url);\n + BoundRequestBuilder requestBuilder = asyncHttpClient.prepare("{{ method|upper }}", url); '''; - final String kTemplateUrlQueryParam = ''' - requestBuilder{% for name, value in queryParams %} - .addQueryParam("{{ name }}", "{{ value }}"){% endfor %};\n + final String kTemplateUrlQueryParam = ''' + {% for name, value in queryParams %} {% for v in value %} + requestBuilder.addQueryParam("{{ name }}", "{{ v }}"); {% endfor %}{% endfor %}\n '''; - final String kTemplateRequestHeader = ''' requestBuilder{% for name, value in headers %} .addHeader("{{ name }}", "{{ value }}"){% endfor %};\n @@ -158,7 +157,7 @@ public class Main { result += templateRequestCreation.render({"method": method.name}); // setting up query parameters - var params = uri.queryParameters; + var params = requestModel.enabledParamsMap; if (params.isNotEmpty) { var templateUrlQueryParam = jj.Template(kTemplateUrlQueryParam); result += templateUrlQueryParam.render({"queryParams": params}); diff --git a/lib/codegen/java/okhttp.dart b/lib/codegen/java/okhttp.dart index e9b849a72..31e0e7be0 100644 --- a/lib/codegen/java/okhttp.dart +++ b/lib/codegen/java/okhttp.dart @@ -36,16 +36,16 @@ import okhttp3.MultipartBody;"""; '''; - final String kTemplateUrlQuery = ''' +final String kTemplateUrlQuery = ''' + HttpUrl.Builder urlBuilder = HttpUrl.parse("{{url}}").newBuilder(); + {% for name, value in queryParams %}{% for v in value %} + urlBuilder.addQueryParameter("{{ name }}", "{{ v }}");{% endfor %}{% endfor %} + HttpUrl url = urlBuilder.build(); + '''; - HttpUrl url = HttpUrl.parse("{{url}}").newBuilder() - {{params}} - .build(); - -'''; String kTemplateRequestBody = ''' - + MediaType mediaType = MediaType.parse("{{contentType}}"); RequestBody body = RequestBody.create({{body}}, mediaType); @@ -107,12 +107,12 @@ import okhttp3.MultipartBody;"""; String url = stripUriParams(uri); if (uri.hasQuery) { - var params = uri.queryParameters; + var params = requestModel.enabledParamsMap; if (params.isNotEmpty) { hasQuery = true; var templateParams = jj.Template(kTemplateUrlQuery); result += templateParams - .render({"url": url, "params": getQueryParams(params)}); + .render({"url": url, "queryParams": params}); } } if (!hasQuery) { @@ -172,12 +172,6 @@ import okhttp3.MultipartBody;"""; } } - String getQueryParams(Map params) { - final paramStrings = params.entries - .map((entry) => '.addQueryParameter("${entry.key}", "${entry.value}")') - .toList(); - return paramStrings.join('\n '); - } String getHeaders(Map headers) { String result = ""; diff --git a/lib/codegen/java/unirest.dart b/lib/codegen/java/unirest.dart index ad3a3e99f..563476770 100644 --- a/lib/codegen/java/unirest.dart +++ b/lib/codegen/java/unirest.dart @@ -3,7 +3,7 @@ import 'package:jinja/jinja.dart' as jj; class JavaUnirestGen { final String kStringUnirestImports = ''' -import kong.unirest.core.*; +import kong.unirest.*; '''; @@ -27,18 +27,21 @@ public class Main { '''; final String kTemplateRequestCreation = ''' - HttpResponse response = Unirest - .{{method}}(requestURL)\n + HttpResponse response = Unirest.{{method}}(requestURL)\n '''; final String kTemplateRequestHeader = ''' .header("{{name}}", "{{value}}")\n '''; - final String kTemplateUrlQueryParam = ''' - .queryString("{{name}}", "{{value}}")\n + final String kTemplateUrlQueryParam = ''' + {% for name, value in queryParams %}{% for v in value -%} + .queryString("{{name}}", "{{v}}") + {% endfor %}{% endfor %} '''; + + final String kTemplateRequestTextFormData = ''' .field("{{name}}", "{{value}}")\n '''; @@ -52,7 +55,7 @@ public class Main { '''; final String kStringRequestEnd = """ - .asJson(); + .asJson(); System.out.println(response.getStatus()); System.out.println(response.getBody()); } @@ -125,14 +128,11 @@ public class Main { // ~~~~~~~~~~~~~~~~~~ query parameters start ~~~~~~~~~~~~~~~~~~ - if (uri.hasQuery) { - var params = uri.queryParameters; - var templateUrlQueryParam = jj.Template(kTemplateUrlQueryParam); - params.forEach((name, value) { - result += - templateUrlQueryParam.render({"name": name, "value": value}); - }); - } + + var params = requestModel.enabledParamsMap; + var templateUrlQueryParam = jj.Template(kTemplateUrlQueryParam); + result += templateUrlQueryParam.render({"queryParams": params}); + // ~~~~~~~~~~~~~~~~~~ query parameters end ~~~~~~~~~~~~~~~~~~ diff --git a/lib/codegen/js/axios.dart b/lib/codegen/js/axios.dart index e6651976a..11338791a 100644 --- a/lib/codegen/js/axios.dart +++ b/lib/codegen/js/axios.dart @@ -69,16 +69,15 @@ axios(config) "method": harJson["method"].toLowerCase(), }); - var params = harJson["queryString"]; - if (params.isNotEmpty) { - var templateParams = jj.Template(kTemplateParams); - var m = {}; - for (var i in params) { - m[i["name"]] = i["value"]; + var enabledParams = requestModel.enabledParamsMap; + + if (enabledParams.isNotEmpty) { + var templateParams = jj.Template(kTemplateParams); + result += templateParams.render({ + "params": padMultilineString(kJsonEncoder.convert(enabledParams), 2) + }); } - result += templateParams - .render({"params": padMultilineString(kJsonEncoder.convert(m), 2)}); - } + var headers = harJson["headers"]; if (headers.isNotEmpty || requestModel.hasFormData) { diff --git a/lib/codegen/js/fetch.dart b/lib/codegen/js/fetch.dart index 5f610738b..d08b2daa9 100644 --- a/lib/codegen/js/fetch.dart +++ b/lib/codegen/js/fetch.dart @@ -15,8 +15,12 @@ import { {% if hasFileInFormData %}fileFromSync, {% endif %}FormData } from 'nod """; - String kTemplateStart = """const url = '{{url}}'; - + String kTemplateStart = """const url = new URL('{{url}}'); +{% for key, value in params -%} +{% for item in value -%} +url.searchParams.append('{{key}}', '{{item}}'); +{% endfor -%} +{% endfor -%} const options = { method: '{{method}}' """; @@ -63,7 +67,7 @@ fetch(url, options) : requestModel.hasFileInFormData ? "// refer https://github.com/foss42/apidash/issues/293#issuecomment-1995208098 for details regarding integration\n\n" : ""; - if (requestModel.hasFormData) { + if (requestModel.hasFormData) { result += "const payload = new FormData();\n"; var templateMultiPartBody = jj.Template(kMultiPartBodyTemplate); var formFileCounter = 1; @@ -83,15 +87,17 @@ fetch(url, options) var harJson = requestModelToHARJsonRequest(requestModel, useEnabled: true); + var params = requestModel.enabledParamsMap; var templateStart = jj.Template(kTemplateStart); result += templateStart.render({ - "url": harJson["url"], + "url": stripUrlParams(requestModel.url), "method": harJson["method"], + "params": params, }); var headers = harJson["headers"]; - + if (headers.isNotEmpty) { var templateHeader = jj.Template(kTemplateHeader); var m = {}; diff --git a/lib/codegen/julia/http.dart b/lib/codegen/julia/http.dart index 3425dc099..60224964c 100644 --- a/lib/codegen/julia/http.dart +++ b/lib/codegen/julia/http.dart @@ -13,15 +13,19 @@ url = "{{url}}" \n """; - String kTemplateParams = """ +String kTemplateParams = """ params = Dict( {%- for name, value in params %} - "{{ name }}" => "{{ value }}", + "{{ name }}" =>[ + {%- for v in value -%}"{{ v }}"{%- if not loop.last -%}, {%- endif -%}{%- endfor -%} + ], {%- endfor %} ) \n """; + + String kTemplateHeaders = """ headers = Dict( {%- for name, value in headers %} @@ -64,7 +68,7 @@ response = HTTP.request("{{ method | upper }}", url final String kStringRequestEnd = r""" , status_exception=false) -println("Status Code: $(response.status) $(HTTP.StatusCodes.statustext(response.status))") +println("Status Code: $(response.status)") println("Response Body: \n$(String(response.body))") """; @@ -91,14 +95,14 @@ println("Response Body: \n$(String(response.body))") final templateUrl = jj.Template(kTemplateUrl); result += templateUrl.render({"url": stripUriParams(uri)}); - if (uri.hasQuery) { - var params = uri.queryParameters; + + var params = requestModel.enabledParamsMap; if (params.isNotEmpty) { hasQuery = true; final templateParams = jj.Template(kTemplateParams); result += templateParams.render({"params": params}); } - } + if (requestModel.hasJsonData || requestModel.hasTextData) { addHeaderForBody = true; diff --git a/lib/codegen/kotlin/okhttp.dart b/lib/codegen/kotlin/okhttp.dart index 418c0ba96..319ca80e3 100644 --- a/lib/codegen/kotlin/okhttp.dart +++ b/lib/codegen/kotlin/okhttp.dart @@ -36,12 +36,18 @@ import okhttp3.MediaType.Companion.toMediaType"""; '''; - final String kTemplateUrlQuery = ''' + final String kTemplateUrlQuery = """ val url = "{{url}}".toHttpUrl().newBuilder() -{{params}} .build() +{%- for name, values in params %} + {%- for value in values %} + .addQueryParameter("{{ name }}", "{{ value }}") + {%- endfor %} +{%- endfor %} + .build() + +"""; -'''; String kTemplateRequestBody = ''' @@ -95,15 +101,13 @@ import okhttp3.MediaType.Companion.toMediaType"""; if (uri != null) { String url = stripUriParams(uri); - if (uri.hasQuery) { - var params = uri.queryParameters; + var params = requestModel.enabledParamsMap; if (params.isNotEmpty) { hasQuery = true; var templateParams = jj.Template(kTemplateUrlQuery); result += templateParams - .render({"url": url, "params": getQueryParams(params)}); + .render({"url": url, "params": params}); } - } if (!hasQuery) { var templateUrl = jj.Template(kTemplateUrl); result += templateUrl.render({"url": url}); diff --git a/lib/codegen/php/curl.dart b/lib/codegen/php/curl.dart index 24ff2579f..b7eab3fa3 100644 --- a/lib/codegen/php/curl.dart +++ b/lib/codegen/php/curl.dart @@ -35,11 +35,9 @@ $request_body = '{{body}}'; //defining query parameters String kTemplateParams = r''' $queryParams = [ -{%- for name, value in params %} - '{{ name }}' => '{{ value }}', -{%- endfor %} +{{params}} ]; -$uri .= '?' . http_build_query($queryParams); +$uri .= '?' . http_build_query($queryParams, '', '&'); '''; @@ -82,9 +80,9 @@ curl_setopt_array($request, [ $response = curl_exec($request); +$httpCode = curl_getinfo($request, CURLINFO_HTTP_CODE); curl_close($request); -$httpCode = curl_getinfo($request, CURLINFO_HTTP_CODE); echo "Status Code: " . $httpCode . "\n"; echo $response . "\n"; '''; @@ -122,13 +120,19 @@ echo $response . "\n"; } //checking and adding query params - if (uri.hasQuery) { - if (requestModel.enabledParamsMap.isNotEmpty) { - var templateParams = jj.Template(kTemplateParams); - result += templateParams - .render({"params": requestModel.enabledParamsMap}); - } - } + var params = requestModel.enabledParamsMap; +if (params.isNotEmpty) { + var templateParams = jj.Template(kTemplateParams); + List paramList = []; + + params.forEach((key, value) { + paramList.add("'$key' => [${value.map((v) => "'$v'").join(", ")}]"); + }); + + result += templateParams.render({ + "params": paramList.join(",\n"), + }); +} var headers = requestModel.enabledHeadersMap; if (requestModel.hasBody && !requestModel.hasContentTypeHeader) { diff --git a/lib/codegen/php/guzzle.dart b/lib/codegen/php/guzzle.dart index d6fe79f64..9a6697bf2 100644 --- a/lib/codegen/php/guzzle.dart +++ b/lib/codegen/php/guzzle.dart @@ -20,14 +20,14 @@ use GuzzleHttp\\Psr7\\Request; """; - String kTemplateParams = """ +String kTemplateParams = """ \$queryParams = [ {{params}} ]; -\$queryParamsStr = '?' . http_build_query(\$queryParams); +\$queryParamsStr = '?' . http_build_query(\$queryParams, '','&'); +"""; -"""; String kTemplateHeader = """ \$headers = [ @@ -80,17 +80,20 @@ echo $res->getBody(); result += renderedMultiPartBody; } - var params = requestModel.enabledParamsMap; - if (params.isNotEmpty) { - var templateParams = jj.Template(kTemplateParams); - List paramList = []; - params.forEach((key, value) { - paramList.add("'$key' => '$value'"); - }); - result += templateParams.render({ - "params": paramList.join(",\n"), - }); - } +var params = requestModel.enabledParamsMap; +if (params.isNotEmpty) { + var templateParams = jj.Template(kTemplateParams); + List paramList = []; + + params.forEach((key, value) { + paramList.add("'$key' => [${value.map((v) => "'$v'").join(", ")}]"); + }); + + result += templateParams.render({ + "params": paramList.join(",\n"), + }); +} + var headers = requestModel.enabledHeadersMap; List headerList = []; diff --git a/lib/codegen/php/http_plug.dart b/lib/codegen/php/http_plug.dart index 299c1a93e..f6e6d5b73 100644 --- a/lib/codegen/php/http_plug.dart +++ b/lib/codegen/php/http_plug.dart @@ -19,10 +19,12 @@ use Http\\Discovery\\Psr18ClientDiscovery; """; String kTemplateParams = """ -\$queryParams = [{{params}}]; -\$uri .= '?' . http_build_query(\$queryParams); + \$queryParams = [ + {{params}} + ]; + \$uri .= '?' . http_build_query(\$queryParams,'','&'); -"""; + """; String kTemplateRequestInit = """ \$request = Psr17FactoryDiscovery::findRequestFactory()->createRequest('{{method}}', \$uri); @@ -89,19 +91,19 @@ echo \$response->getBody(); var templateUri = jj.Template(kTemplateUri); result += templateUri.render({"uri": stripUriParams(uri)}); - if (uri.hasQuery) { - var params = uri.queryParameters; - if (params.isNotEmpty) { - var templateParams = jj.Template(kTemplateParams); - List queryList = []; - for (MapEntry entry in params.entries) { - String entryStr = "\"${entry.key}\" => \"${entry.value}\""; - queryList.add(entryStr); - } - String paramsString = "\n ${queryList.join(",\n ")}\n"; - result += templateParams.render({"params": paramsString}); - } - } + var params = requestModel.enabledParamsMap; + if (params.isNotEmpty) { + var templateParams = jj.Template(kTemplateParams); + List paramList = []; + + params.forEach((key, value) { + paramList.add("'$key' => [${value.map((v) => "'$v'").join(", ")}]"); + }); + + result += templateParams.render({ + "params": paramList.join(",\n"), + }); + } var templateRequestInit = jj.Template(kTemplateRequestInit); result += templateRequestInit diff --git a/lib/codegen/python/http_client.dart b/lib/codegen/python/http_client.dart index a2c018082..9240e670a 100644 --- a/lib/codegen/python/http_client.dart +++ b/lib/codegen/python/http_client.dart @@ -12,9 +12,8 @@ from codecs import encode String kTemplateParams = """ from urllib.parse import urlencode - -queryParams = {{params}} -queryParamsStr = '?' + urlencode(queryParams) +params = { {{params}} } +queryParamsStr = '?' + urlencode(params,doseq=True) """; @@ -102,17 +101,23 @@ body = b'\r\n'.join(dataList) ); Uri? uri = rec.$1; + var params = requestModel.enabledParamsMap; + if (params.isNotEmpty) { + hasQuery=true; + var templateParams = jj.Template(kTemplateParams); + List paramList = []; + + params.forEach((key, value) { + paramList.add("'$key': [${value.map((v) => "'$v'").join(", ")}]"); + }); + + result += templateParams.render({ + "params": paramList.join(",\n"), + }); + } if (uri != null) { - if (uri.hasQuery) { - var params = uri.queryParameters; - if (params.isNotEmpty) { - hasQuery = true; - var templateParams = jj.Template(kTemplateParams); - var paramsString = kJsonEncoder.convert(params); - result += templateParams.render({"params": paramsString}); - } - } + if (requestModel.hasBody) { hasBody = true; diff --git a/lib/codegen/python/requests.dart b/lib/codegen/python/requests.dart index ef2a19faa..fd22c7743 100644 --- a/lib/codegen/python/requests.dart +++ b/lib/codegen/python/requests.dart @@ -12,11 +12,9 @@ url = '{{url}}' """; - String kTemplateParams = """ - -params = {{params}} - -"""; +String kTemplateParams = """ +params = { {{params}} } +"""; String kTemplateBody = """ @@ -100,15 +98,20 @@ print('Response Body:', response.text) 'hasFormData': requestModel.hasFormData }); - if (uri.hasQuery) { - var params = uri.queryParameters; - if (params.isNotEmpty) { - hasQuery = true; - var templateParams = jj.Template(kTemplateParams); - var paramsString = kJsonEncoder.convert(params); - result += templateParams.render({"params": paramsString}); - } - } + var params = requestModel.enabledParamsMap; + if (params.isNotEmpty) { + hasQuery=true; + var templateParams = jj.Template(kTemplateParams); + List paramList = []; + + params.forEach((key, value) { + paramList.add("'$key': [${value.map((v) => "'$v'").join(", ")}]"); + }); + + result += templateParams.render({ + "params": paramList.join(",\n"), + }); + } if (requestModel.hasFormData) { hasBody = true; diff --git a/lib/codegen/ruby/faraday.dart b/lib/codegen/ruby/faraday.dart index 11d73946d..1a903c34c 100644 --- a/lib/codegen/ruby/faraday.dart +++ b/lib/codegen/ruby/faraday.dart @@ -59,7 +59,8 @@ response = conn.{{ method|lower }}(REQUEST_URL{% if doesMethodAcceptBody and con final String kTemplateRequestParams = """ req.params = { -{% for key, val in params %} "{{ key }}" => "{{ val }}",\n{% endfor %} } + {% for key, val in params %}"{{ key }}" => {% if val is list %}[{% for v in val %}"{{ v|string }}"{% if not loop.last %}, {% endif %}{% endfor %}]{% else %}"{{ val|string }}"{% endif %}, + {% endfor %}} """; @@ -155,12 +156,9 @@ puts "Response Body: #{response.body}" result += templateRequestHeaders.render({"headers": headers}); } - if (uri.hasQuery) { - var params = uri.queryParameters; - if (params.isNotEmpty) { - var templateRequestParams = jj.Template(kTemplateRequestParams); - result += templateRequestParams.render({"params": params}); - } + if (requestModel.enabledParamsMap.isNotEmpty) { + var templateRequestParams = jj.Template(kTemplateRequestParams); + result += templateRequestParams.render({"params": requestModel.enabledParamsMap}); } if (requestModel.hasBody && requestModel.method == HTTPVerb.delete) { diff --git a/lib/codegen/ruby/net_http.dart b/lib/codegen/ruby/net_http.dart index 519c5cfa7..e58957372 100644 --- a/lib/codegen/ruby/net_http.dart +++ b/lib/codegen/ruby/net_http.dart @@ -6,6 +6,16 @@ class RubyNetHttpCodeGen { require "net/http" url = URI("{{url}}") +"""; + + String kTemplateRequestParams = """ +\nparams = { +{% for key, val in params %} "{{ key }}" => [{% for v in val %}"{{ v|string }}"{% if not loop.last %}, {% endif %}{% endfor %}], +{% endfor %}} +url.query = URI.encode_www_form(params)\n +"""; + + String kTemplateConnectionAndRequest = """ https = Net::HTTP.new(url.host, url.port) {% if check == "https" %}https.use_ssl = true{% endif %} request = Net::HTTP::{{method}}.new(url) @@ -13,7 +23,8 @@ request = Net::HTTP::{{method}}.new(url) String kTemplateHeader = """ {% for key, value in headers %} -request["{{key}}"] = "{{value}}"{% endfor %} +request["{{key}}"] = "{{value}}" +{% endfor %} """; String kTemplateBody = """ @@ -31,7 +42,11 @@ HEREDOC response = https.request(request) puts "Response Code: #{response.code}" -{% if method != "head" %}puts "Response Body: #{response.body}"{% else %}puts "Response Body: #{response.to_hash}"{% endif %} +{% if method != "head" %} +puts "Response Body: #{response.body}" +{% else %} +puts "Response Headers: #{response.to_hash}" +{% endif %} """; @@ -52,7 +67,17 @@ puts "Response Code: #{response.code}" var templateStart = jj.Template(kTemplateStart); result += templateStart.render({ - "url": uri.query.isEmpty ? stripUriParams(uri) : uri, + "url": uri.toString().split('?').first, + }); + if (requestModel.enabledParamsMap.isNotEmpty) { + var templateRequestParams = jj.Template(kTemplateRequestParams); + result += templateRequestParams.render({ + "params": requestModel.enabledParamsMap, + }); + } + + var connectionTemplate = jj.Template(kTemplateConnectionAndRequest); + result += connectionTemplate.render({ "method": requestModel.method.name.capitalize(), "check": uri.scheme, }); @@ -78,8 +103,7 @@ puts "Response Code: #{response.code}" } if (requestModel.hasFormData) { - result += "\n"; - result += "form_data = ["; + result += "\nform_data = ["; var templateMultiPartBody = jj.Template(kMultiPartBodyTemplate); int length = requestModel.formDataMapList.length; @@ -90,16 +114,12 @@ puts "Response Code: #{response.code}" "value": element["value"], "type": element["type"] }); - length -= 1; - if (length == 0) { - result += "]"; - } else { - result += "],"; - } + result += "]"; + if (--length > 0) result += ", "; } result += "]\n"; result += - "request.set_form form_data, '${ContentType.formdata.header}'"; + "request.set_form form_data, '${ContentType.formdata.header}'\n"; } result += jj.Template(kStringRequest) diff --git a/lib/codegen/rust/actix.dart b/lib/codegen/rust/actix.dart index acc752ead..e9485aa1f 100644 --- a/lib/codegen/rust/actix.dart +++ b/lib/codegen/rust/actix.dart @@ -13,11 +13,20 @@ use std::io::Read; async fn main() -> Result<(), Box> { let url = "{{url}}"; let client = awc::Client::default(); - + let mut request = client.{{method}}(url); """; - String kTemplateParams = - """\n .query(&{{ params }})\n .unwrap()"""; +String kTemplateParams = """ + + let query_params = [ + {%- for key, values in params %} + {%- for val in values %} + ("{{key}}", "{{val}}"), + {%- endfor %} + {%- endfor %} + ]; + request = request.query(&query_params).unwrap(); +"""; String kTemplateBody = """ @@ -37,11 +46,6 @@ async fn main() -> Result<(), Box> { String kTemplateFormHeaderContentType = ''' multipart/form-data; boundary={{boundary}}'''; - String kTemplateRequest = """ - - let mut response = client\n .{{method}}(url) -"""; - final String kStringFormDataBody = r""" struct FormDataItem { @@ -92,11 +96,11 @@ multipart/form-data; boundary={{boundary}}'''; let payload = build_data_list(form_data_items); """; - String kStringRequestBody = """\n .send_body(payload)"""; + String kStringRequestBody = """\n let mut response = request.send_body(payload)"""; - String kStringRequestJson = """\n .send_json(&payload)"""; + String kStringRequestJson = """\n let mut response = request.send_json(&payload)"""; - String kStringRequestNormal = """\n .send()"""; + String kStringRequestNormal = """\n let mut response = request.send()"""; final String kStringRequestEnd = """\n .await\n .unwrap(); @@ -127,9 +131,10 @@ multipart/form-data; boundary={{boundary}}'''; ); Uri? uri = rec.$1; if (uri != null) { + var baseUrl = stripUriParams(uri); var templateStartUrl = jj.Template(kTemplateStart); result += templateStartUrl.render({ - "url": stripUriParams(uri), + "url": baseUrl, 'isFormDataRequest': requestModel.hasFormData, "method": requestModel.method.name.toLowerCase() }); @@ -160,23 +165,17 @@ multipart/form-data; boundary={{boundary}}'''; }, ); } - var templateRequest = jj.Template(kTemplateRequest); - result += templateRequest.render({ - "method": method.name.toLowerCase(), - }); - - if (uri.hasQuery) { - var params = uri.queryParameters; - if (params.isNotEmpty) { - var tupleStrings = params.entries - .map((entry) => '("${entry.key}", "${entry.value}")') - .toList(); - var paramsString = "[${tupleStrings.join(', ')}]"; - var templateParms = jj.Template(kTemplateParams); - result += templateParms.render({"params": paramsString}); - } - } - + + var params = requestModel.enabledParamsMap; + + if (params.isNotEmpty) { + var templateParams = jj.Template(kTemplateParams); + result += templateParams.render({ + "method": method.name.toLowerCase(), + "params": params, + }); + } + var headersList = requestModel.enabledHeaders; if (headersList != null || hasBody || requestModel.hasFormData) { var headers = requestModel.enabledHeadersMap; diff --git a/lib/codegen/rust/curl_rust.dart b/lib/codegen/rust/curl_rust.dart index 727f0b2cd..b612d4b47 100644 --- a/lib/codegen/rust/curl_rust.dart +++ b/lib/codegen/rust/curl_rust.dart @@ -1,6 +1,6 @@ + import 'package:apidash_core/apidash_core.dart'; import 'package:jinja/jinja.dart' as jj; -import '../../utils/utils.dart'; class RustCurlCodeGen { final String kTemplateStart = """use curl::easy::Easy; @@ -10,11 +10,23 @@ class RustCurlCodeGen { fn main() { let mut easy = Easy::new(); let mut data = Vec::new(); - + let base_url = "{{baseUrl}}"; """; - String kTemplateUrl = """ - easy.url("{{url}}").unwrap(); + String kTemplateUrlParams = """ + + {% if params %} + let params: Vec<(&str, Vec<&str>)> = vec![ + {%- for key, values in params %} + ("{{key}}", vec![{% for val in values %}"{{val}}", {% endfor %}]), + {%- endfor %} + ]; + let query_string: String = params.iter().flat_map(|(key, values)| values.iter().map(move |val| format!("{}={}", key, val))) .collect::>().join("&"); + let url = format!("{}?{}", base_url, query_string); + {% else %} + let url = base_url.to_string(); + {% endif %} + """; String kTemplateMethod = """ @@ -50,7 +62,7 @@ fn main() { .add().unwrap(); {% endfor %} easy.httppost(form).unwrap(); - """; +"""; String kTemplateHeader = """ {% if headers %}let mut list = List::new();{% for header, value in headers %} @@ -62,6 +74,7 @@ fn main() { final String kTemplateEnd = """ { + easy.url(&url).unwrap(); let mut transfer = easy.transfer(); transfer.write_function(|new_data| { data.extend_from_slice(new_data); @@ -71,7 +84,6 @@ fn main() { } let response_body = String::from_utf8_lossy(&data); - println!("Response body: {}", response_body); println!("Response code: {}", easy.response_code().unwrap()); }"""; @@ -86,7 +98,8 @@ fn main() { "hasJsonBody": requestModel.hasJsonData, "hasHeaders": (requestModel.enabledHeaders != null && requestModel.enabledHeaders!.isNotEmpty) || - (requestModel.hasJsonData || requestModel.hasTextData) + (requestModel.hasJsonData || requestModel.hasTextData), + "baseUrl": url.split('?').first, }); var rec = getValidRequestUri( @@ -95,16 +108,21 @@ fn main() { ); Uri? uri = rec.$1; - var harJson = - requestModelToHARJsonRequest(requestModel, useEnabled: true); + + if (uri != null) { - var templateUrl = jj.Template(kTemplateUrl); - result += templateUrl.render({"url": harJson["url"]}); + var params = requestModel.enabledParamsMap; - var methodTemplate = jj.Template(kTemplateMethod); - result += methodTemplate.render({"method": requestModel.method.name}); + var templateUrlParams = jj.Template(kTemplateUrlParams); + result += templateUrlParams.render({ + "params": params.isNotEmpty ? params : null, + }); - if (uri != null) { + // Method + var methodTemplate = jj.Template(kTemplateMethod); + result += methodTemplate.render({"method": requestModel.method.name.toLowerCase()}); + + // Request body if (requestModel.hasTextData) { var templateBody = jj.Template(kTemplateRawBody); result += templateBody.render({"body": requestModel.body}); @@ -117,7 +135,7 @@ fn main() { "fields": requestModel.formDataMapList, }); } - + var headersList = requestModel.enabledHeaders; if (headersList != null || requestModel.hasBody) { var headers = requestModel.enabledHeadersMap; @@ -129,10 +147,10 @@ fn main() { var templateHeader = jj.Template(kTemplateHeader); result += templateHeader.render({ "headers": headers, - }); + }); } } - + result += kTemplateEnd; } diff --git a/lib/codegen/rust/hyper.dart b/lib/codegen/rust/hyper.dart index 1acaab55c..f88f46689 100644 --- a/lib/codegen/rust/hyper.dart +++ b/lib/codegen/rust/hyper.dart @@ -5,82 +5,87 @@ import 'package:jinja/jinja.dart' as jj; class RustHyperCodeGen { final String kTemplateStart = """ {% if hasForm %}extern crate hyper_multipart_rfc7578 as hyper_multipart; -{% endif %}use hyper::{Body, Client, Request, Uri}; +{% endif %}use hyper::{Body, Client, Request}; {% if isHttps %}use hyper_tls::HttpsConnector; {% else %}use hyper::client::HttpConnector; {% endif %}{% if hasForm %}use hyper_multipart::client::multipart; {% endif %}{% if hasJsonBody %}use serde_json::json; {% endif %}use tokio; +use url::Url; #[tokio::main] async fn main() -> Result<(), Box> { let http{% if isHttps %}s{% endif %} = Http{% if isHttps %}s{% endif %}Connector::new(); let client = Client::builder().build::<_, hyper::Body>(http{% if isHttps %}s{% endif %}); - let url = "{{ url }}".parse::().unwrap(); + let mut url = Url::parse("{{ baseUrl }}")?; + """; + final String kTemplateParams = """ + {% for key, values in params %}{% for val in values %} + url.query_pairs_mut().append_pair("{{ key }}", "{{ val }}");{% endfor %}{% endfor %} """; final String kTemplateMethod = """ let req_builder = Request::builder() - .method("{{ method }}") - .uri(url) + .method("{{ method }}").uri(url.as_str()) """; + final String kTemplateMethodNoHeadersButForm = """ let req_builder = Request::builder() - .method("{{ method }}") - .uri(url); + .method("{{ method }}") + .uri(url.as_str()); """; final String kTemplateHeaders = """ - {% for key, val in headers %} - .header("{{ key }}", "{{ val }}") - {% endfor %}"""; + {% for key, val in headers %} + .header("{{ key }}", "{{ val }}") + {% endfor %}"""; final String kTemplateHeadersFormData = """ - {% for key, val in headers %} - .header("{{ key }}", "{{ val }}"){% if loop.last %};{% endif %} - {% endfor %} + {% for key, val in headers %} + .header("{{ key }}", "{{ val }}"){% if loop.last %};{% endif %} + {% endfor %} """; final String kTemplateBody = """ - - .body(Body::from(r#"{{ body }}"#))?;\n + + .body(Body::from(r#"{{ body }}"#))?;\n """; final String kTemplateJsonBody = """ - - .body(Body::from(json!({{ body }}).to_string()))?;\n + + .body(Body::from(json!({{ body }}).to_string()))?;\n """; final String kTemplateEmptyBody = """ - .body(Body::empty())?;\n + .body(Body::empty())?;\n """; final String kTemplateFormData = """ - + let mut form = multipart::Form::default(); {%- for field in fields_list %} - {%- if field.type == "file" %} + {%- if field.type == "file" %} form.add_file("{{ field.name }}", r"{{ field.value }}").unwrap(); - {%- else %} + {%- else %} form.add_text("{{ field.name }}", "{{ field.value }}"); - {%- endif %} + {%- endif %} {%- endfor %} let req = form.set_body_convert::(req_builder).unwrap(); - - """; + +"""; final String kTemplateEndForm = """ - let res = client.request(req).await?; + let res = client.request(req).await?; let status = res.status(); let body_bytes = hyper::body::to_bytes(res).await?; let body = String::from_utf8(body_bytes.to_vec())?; println!("Response Status: {}", status); println!("Response: {:?}", body); - + """; @@ -108,16 +113,30 @@ async fn main() -> Result<(), Box> { String url = requestModel.url; var rec = getValidRequestUri(url, requestModel.enabledParams); Uri? uri = rec.$1; - + if (uri != null) { + var baseUrl = url.split('?').first; + + // Get query parameters + var params = requestModel.enabledParamsMap; + var headers = requestModel.enabledHeadersMap; + + // Generate template start with base URL result += jj.Template(kTemplateStart).render({ - "url": uri, + "baseUrl": baseUrl, "isHttps": uri.scheme == "https" ? true : false, 'hasJsonBody': requestModel.hasJsonData, 'hasForm': requestModel.hasFormData, }); - + + // Add query parameters if available + if (params.isNotEmpty) { + result += jj.Template(kTemplateParams).render({ + "params": params, + }); + } + if (requestModel.hasFormData && headers.isEmpty) { result += jj.Template(kTemplateMethodNoHeadersButForm).render({ "method": requestModel.method.name.toUpperCase(), @@ -127,9 +146,8 @@ async fn main() -> Result<(), Box> { "method": requestModel.method.name.toUpperCase(), }); } - + // Add headers if available - if (headers.isNotEmpty) { if (requestModel.hasFormData) { result += jj.Template(kTemplateHeadersFormData) @@ -139,7 +157,7 @@ async fn main() -> Result<(), Box> { jj.Template(kTemplateHeaders).render({"headers": headers}); } } - + // Handle body (JSON or raw) var requestBody = requestModel.body; if (requestModel.hasFormData) { @@ -157,19 +175,20 @@ async fn main() -> Result<(), Box> { } else if (requestModel.hasTextData) { result += jj.Template(kTemplateBody).render({"body": requestBody}); } + // End request - if (requestModel.hasFormData && requestModel.method != HTTPVerb.get) { result += kTemplateEndForm; } else { result += kTemplateRequestEnd; } + result += kTemplateEnd; } - + return result; } catch (e) { return null; } } -} +} \ No newline at end of file diff --git a/lib/codegen/rust/reqwest.dart b/lib/codegen/rust/reqwest.dart index 1e72807b0..aa260fb38 100644 --- a/lib/codegen/rust/reqwest.dart +++ b/lib/codegen/rust/reqwest.dart @@ -7,26 +7,33 @@ class RustReqwestCodeGen { final String kTemplateStart = """fn main() -> Result<(), Box> { let client = reqwest::blocking::Client::new(); - let url = "{{url}}"; + let url = "{{url}}";\n +"""; + String kTemplateParamsDef = """ + let query_params = [ + {%- for key, values in params %} + {%- for val in values %} + ("{{key}}", "{{val}}"), + {%- endfor %} + {%- endfor %} + ]; """; - String kTemplateParams = """\n .query(&{{params}})"""; + String kTemplateParamsChain = """\n .query(&query_params)"""; String kTemplateBody = """ let payload = r#"{{body}}"#; - """; String kTemplateJson = """ let payload = serde_json::json!({{body}}); - """; String kTemplateHeaders = - """\n {% for key, val in headers -%}.header("{{key}}", "{{val}}"){% if not loop.last %}{{ '\n ' }}{% endif %}{%- endfor -%}"""; + """\n {% for key, val in headers -%}.header("{{key}}", "{{val}}"){% if not loop.last %}{{ '\n ' }}{% endif %}{%- endfor -%}"""; String kTemplateRequest = """ @@ -79,7 +86,7 @@ class RustReqwestCodeGen { String? getCode( HttpRequestModel requestModel, - ) { + ) { try { String result = ""; bool hasBody = false; @@ -90,14 +97,12 @@ class RustReqwestCodeGen { var rec = getValidRequestUri( url, requestModel.enabledParams, - ); + ); Uri? uri = rec.$1; if (uri != null) { var templateStartUrl = jj.Template(kTemplateStart); result += templateStartUrl.render({ - "url": stripUriParams(uri), - 'isFormDataRequest': requestModel.hasFormData, - 'isJson': requestModel.bodyContentType == ContentType.json + "url": url.split('?').first }); var method = requestModel.method; @@ -121,28 +126,26 @@ class RustReqwestCodeGen { var formDataBodyData = jj.Template(kStringFormDataBody); result += formDataBodyData.render( { - "fields_list": requestModel.formDataMapList, - }, + "fields_list": requestModel.formDataMapList, + }, ); } + var params = requestModel.enabledParamsMap; + if (params.isNotEmpty) { + var templateParamsDef = jj.Template(kTemplateParamsDef); + result += templateParamsDef.render({"params": params}); + } + var templateRequest = jj.Template(kTemplateRequest); result += templateRequest.render({ "method": method.name.toLowerCase(), }); - if (uri.hasQuery) { - var params = uri.queryParameters; - if (params.isNotEmpty) { - var tupleStrings = params.entries - .map((entry) => '("${entry.key}", "${entry.value}")') - .toList(); - var paramsString = "[${tupleStrings.join(', ')}]"; - var templateParams = jj.Template(kTemplateParams); - result += templateParams.render({"params": paramsString}); - } + if (params.isNotEmpty) { + result += kTemplateParamsChain; } - var headersList = requestModel.enabledHeaders; + var headersList = requestModel.enabledHeaders; if (headersList != null || hasBody) { var headers = requestModel.enabledHeadersMap; if (hasBody) { diff --git a/lib/codegen/rust/ureq.dart b/lib/codegen/rust/ureq.dart index 6137f4fc3..9f90214ca 100644 --- a/lib/codegen/rust/ureq.dart +++ b/lib/codegen/rust/ureq.dart @@ -16,16 +16,20 @@ fn main() -> Result<(), ureq::Error> { let url = "{{url}}"; """; - // String kTemplateParams = """\n .query_pairs({{ params }})"""; - String kTemplateParams = - """\n {% for key, val in params -%}.query("{{key}}", "{{val}}"){% if not loop.last %}{{ '\n ' }}{% endif %}{%- endfor -%}"""; + String kTemplateParams = """ + {%- for key, values in params %} + {%- for val in values %} + .query("{{key}}", "{{val}}") + {%- endfor %} + {%- endfor %} +"""; String kTemplateBody = """ let payload = r#"{{body}}"#; - """; + String kTemplateJson = """\n let payload = json!({{body}}); @@ -134,7 +138,6 @@ multipart/form-data; boundary={{boundary}}'''; result += templateStartUrl.render({ "url": stripUriParams(uri), 'isFormDataRequest': requestModel.hasFormData, - "method": requestModel.method.name.toLowerCase() }); @@ -167,12 +170,10 @@ multipart/form-data; boundary={{boundary}}'''; "method": method.name.toLowerCase(), }); - if (uri.hasQuery) { - var params = uri.queryParameters; - if (params.isNotEmpty) { - var templateParms = jj.Template(kTemplateParams); - result += templateParms.render({"params": params}); - } + var params = requestModel.enabledParamsMap; + if (params.isNotEmpty) { + var templateParams = jj.Template(kTemplateParams); + result += templateParams.render({"params": params}); } var headersList = requestModel.enabledHeaders; diff --git a/lib/codegen/swift/alamofire.dart b/lib/codegen/swift/alamofire.dart index b128a7278..8886124f1 100644 --- a/lib/codegen/swift/alamofire.dart +++ b/lib/codegen/swift/alamofire.dart @@ -8,6 +8,15 @@ import Foundation import Alamofire """; + final String kTemplateQueryItems = ''' +var urlComponents = URLComponents(string: "{{baseUrl}}")! +var queryItems = [URLQueryItem]() +{% for param in queryParams %}queryItems.append(URLQueryItem(name: "{{param.name}}", value: "{{param.value}}")) +{% endfor %} +urlComponents.queryItems = queryItems +let url = urlComponents.url! +'''; + final String kTemplateFormData = ''' let multipartFormData = MultipartFormData() {% for param in formData %} {% if param.type == 'text' %}multipartFormData.append(Data("{{param.value}}".utf8), withName: "{{param.name}}") {% elif param.type == 'file' %} @@ -32,8 +41,6 @@ let textData = textString.data(using: .utf8)\n '''; final String kTemplateRequest = """ -let url = "{{url}}" - {% if hasFormData %} AF.upload(multipartFormData: multipartFormData, to: url, method: .{{method}}{% if hasHeaders %}, headers: {{headers}}{% endif %}) {% elif hasBody %} @@ -60,9 +67,37 @@ dispatchMain() try { String result = kTemplateStart; - var rec = - getValidRequestUri(requestModel.url, requestModel.enabledParams); + // Extract base URL and query parameters + var rec = getValidRequestUri(requestModel.url, requestModel.enabledParams); Uri? uri = rec.$1; + if (uri == null) return null; + + // Get base URL without query parameters + String baseUrl = uri.replace(query: '').toString(); + if (baseUrl.endsWith('?')) { + baseUrl = baseUrl.substring(0, baseUrl.length - 1); + } + + // Handle query parameters using URLComponents + var queryParamsList = >[]; + requestModel.enabledParamsMap.forEach((key, values) { + for (var value in values) { + queryParamsList.add({ + 'name': key, + 'value': value, + }); + } + }); + + if (queryParamsList.isNotEmpty) { + var templateQueryItems = jj.Template(kTemplateQueryItems); + result += templateQueryItems.render({ + "baseUrl": baseUrl, + "queryParams": queryParamsList, + }); + } else { + result += 'let url = "$baseUrl"\n'; + } var headers = requestModel.enabledHeadersMap; @@ -105,7 +140,7 @@ dispatchMain() hasBody = true; hasJsonData = true; } - // Handle text data + // Handle text data else if (requestModel.hasTextData) { var templateTextData = jj.Template(kTemplateTextData); result += templateTextData.render({ @@ -131,7 +166,6 @@ dispatchMain() var templateRequest = jj.Template(kTemplateRequest); result += templateRequest.render({ - "url": uri.toString(), "method": requestModel.method.name.toLowerCase(), "headers": headersString, "hasHeaders": hasHeaders, diff --git a/lib/codegen/swift/urlsession.dart b/lib/codegen/swift/urlsession.dart index 015d19afe..a1cc5c3f2 100644 --- a/lib/codegen/swift/urlsession.dart +++ b/lib/codegen/swift/urlsession.dart @@ -50,10 +50,17 @@ let postData = """ '''; - final String kTemplateRequest = """ -var request = URLRequest(url: URL(string: "{{url}}")!) -request.httpMethod = "{{method}}" +final String kTemplateRequest = """ +var urlComponents = URLComponents(string: "{{url}}")! +var queryItems = [URLQueryItem]() + +{% for param in params %} +queryItems.append(URLQueryItem(name: "{{param.key}}", value: "{{param.value}}")){% if not loop.last %}{% else %}{% endif %}{% endfor %} +urlComponents.queryItems = queryItems +let requestUrl = urlComponents.url! +var request = URLRequest(url: requestUrl) +request.httpMethod = "{{method}}" """; final String kTemplateHeaders = """ @@ -73,6 +80,7 @@ request.httpBody = postData """; final String kTemplateEnd = """ + let semaphore = DispatchSemaphore(value: 0) let task = URLSession.shared.dataTask(with: request) { data, response, error in @@ -104,6 +112,18 @@ semaphore.wait() var rec = getValidRequestUri(requestModel.url, requestModel.enabledParams); Uri? uri = rec.$1; + var params = requestModel.enabledParamsMap.entries.expand((entry) { + + var values = entry.value; + + return values.map((value) { + return {'key': entry.key, 'value': value}; + }); + }).toList(); + + + + if (requestModel.hasFormData) { result += kTemplateFormDataImport; @@ -151,8 +171,9 @@ semaphore.wait() var templateRequest = jj.Template(kTemplateRequest); result += templateRequest.render({ - "url": uri.toString(), - "method": requestModel.method.name.toUpperCase() + "url": uri.toString().split('?').first, + "method": requestModel.method.name.toUpperCase(), + "params": params, }); var headers = requestModel.enabledHeadersMap; diff --git a/lib/main.dart b/lib/main.dart index d8a4dd7f3..2830a9087 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,4 +1,5 @@ import 'package:apidash_design_system/apidash_design_system.dart'; + import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'models/models.dart'; diff --git a/lib/screens/history/history_widgets/his_request_pane.dart b/lib/screens/history/history_widgets/his_request_pane.dart index f14350632..a1ae6a80a 100644 --- a/lib/screens/history/history_widgets/his_request_pane.dart +++ b/lib/screens/history/history_widgets/his_request_pane.dart @@ -20,15 +20,15 @@ class HistoryRequestPane extends ConsumerWidget { final codePaneVisible = ref.watch(historyCodePaneVisibleStateProvider); final apiType = ref.watch(selectedHistoryRequestModelProvider .select((value) => value?.metaData.apiType)); - final headersMap = ref.watch(selectedHistoryRequestModelProvider - .select((value) => value?.httpRequestModel.headersMap)) ?? - {}; - final headerLength = headersMap.length; + final headers = ref.watch(selectedHistoryRequestModelProvider + .select((value) => value?.httpRequestModel.headers)) ?? + []; + final headerLength = headers.length; - final paramsMap = ref.watch(selectedHistoryRequestModelProvider - .select((value) => value?.httpRequestModel.paramsMap)) ?? - {}; - final paramLength = paramsMap.length; + final params = ref.watch(selectedHistoryRequestModelProvider + .select((value) => value?.httpRequestModel.params)) ?? + []; + final paramLength = params.length; final hasBody = ref.watch(selectedHistoryRequestModelProvider .select((value) => value?.httpRequestModel.hasBody)) ?? @@ -60,11 +60,11 @@ class HistoryRequestPane extends ConsumerWidget { ], children: [ RequestDataTable( - rows: paramsMap, + rows: params, keyName: kNameURLParam, ), RequestDataTable( - rows: headersMap, + rows: headers, keyName: kNameHeader, ), const HisRequestBody(), @@ -89,7 +89,7 @@ class HistoryRequestPane extends ConsumerWidget { ], children: [ RequestDataTable( - rows: headersMap, + rows: headers, keyName: kNameHeader, ), const HisRequestBody(), diff --git a/lib/utils/har_utils.dart b/lib/utils/har_utils.dart index 31c466ceb..6e0f97e1f 100644 --- a/lib/utils/har_utils.dart +++ b/lib/utils/har_utils.dart @@ -110,14 +110,16 @@ Map requestModelToHARJsonRequest( json["queryString"] = []; json["headers"] = []; - var params = uri.queryParameters; + Map> params = uri.queryParametersAll; if (params.isNotEmpty) { for (final k in params.keys) { - var m = {"name": k, "value": params[k]}; - if (exportMode) { - m["comment"] = ""; + for (final val in params[k]!) { + var m = {"name": k, "value": val}; + if (exportMode) { + m["comment"] = ""; + } + json["queryString"].add(m); } - json["queryString"].add(m); } } diff --git a/lib/widgets/table_request.dart b/lib/widgets/table_request.dart index 7b57ebdf7..d3c6a57c9 100644 --- a/lib/widgets/table_request.dart +++ b/lib/widgets/table_request.dart @@ -2,6 +2,7 @@ import 'package:apidash_design_system/apidash_design_system.dart'; import 'package:flutter/material.dart'; import 'package:data_table_2/data_table_2.dart'; import 'package:apidash/consts.dart'; +import 'package:apidash_core/apidash_core.dart'; import 'field_read_only.dart'; class RequestDataTable extends StatelessWidget { @@ -12,7 +13,7 @@ class RequestDataTable extends StatelessWidget { this.valueName, }); - final Map rows; + final List rows; final String? keyName; final String? valueName; @@ -55,31 +56,29 @@ class RequestDataTable extends StatelessWidget { ), ); - final List dataRows = rows.entries - .map( - (MapEntry entry) => DataRow( - cells: [ - const DataCell(kHSpacer5), - DataCell( - ReadOnlyTextField( - initialValue: entry.key, - decoration: fieldDecoration, - ), - ), - const DataCell( - Text('='), - ), - DataCell( - ReadOnlyTextField( - initialValue: entry.value, - decoration: fieldDecoration, - ), - ), - const DataCell(kHSpacer5), - ], + final List dataRows = rows.map((NameValueModel row) { + return DataRow( + cells: [ + const DataCell(kHSpacer5), + DataCell( + ReadOnlyTextField( + initialValue: row.name, + decoration: fieldDecoration, + ), ), - ) - .toList(); + const DataCell( + Text('='), + ), + DataCell( + ReadOnlyTextField( + initialValue: row.value, + decoration: fieldDecoration, + ), + ), + const DataCell(kHSpacer5), + ], + ); + }).toList(); return Container( margin: kP10, @@ -106,4 +105,4 @@ class RequestDataTable extends StatelessWidget { ), ); } -} +} \ No newline at end of file diff --git a/packages/apidash_core/lib/models/http_request_model.dart b/packages/apidash_core/lib/models/http_request_model.dart index cc2d7411c..f521a1ce7 100644 --- a/packages/apidash_core/lib/models/http_request_model.dart +++ b/packages/apidash_core/lib/models/http_request_model.dart @@ -3,7 +3,7 @@ import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:seed/seed.dart'; import '../extensions/extensions.dart'; import '../utils/utils.dart' - show rowsToFormDataMapList, rowsToMap, getEnabledRows; + show rowsToFormDataMapList, rowsToMap, getEnabledRows,rowsToRequestMap; import '../consts.dart'; part 'http_request_model.freezed.dart'; @@ -34,14 +34,28 @@ class HttpRequestModel with _$HttpRequestModel { _$HttpRequestModelFromJson(json); Map get headersMap => rowsToMap(headers) ?? {}; - Map get paramsMap => rowsToMap(params) ?? {}; + Map> get paramsMap => rowsToRequestMap(params) ?? {}; List? get enabledHeaders => getEnabledRows(headers, isHeaderEnabledList); List? get enabledParams => getEnabledRows(params, isParamEnabledList); Map get enabledHeadersMap => rowsToMap(enabledHeaders) ?? {}; - Map get enabledParamsMap => rowsToMap(enabledParams) ?? {}; +Map> get enabledParamsMap { + var extractedParams = Uri.parse(url).queryParametersAll; + var userParams = rowsToRequestMap(enabledParams) ?? {}; + + extractedParams.forEach((key, values) { + if (userParams.containsKey(key)) { + userParams[key]!.addAll(values); + } else { + userParams[key] = List.from(values); + } + }); + + return userParams; +} + bool get hasContentTypeHeader => enabledHeadersMap.hasKeyContentType(); bool get hasFormDataContentType => bodyContentType == ContentType.formdata; diff --git a/packages/apidash_core/lib/utils/http_request_utils.dart b/packages/apidash_core/lib/utils/http_request_utils.dart index b5eab42cc..c195a8aa8 100644 --- a/packages/apidash_core/lib/utils/http_request_utils.dart +++ b/packages/apidash_core/lib/utils/http_request_utils.dart @@ -100,3 +100,33 @@ String? getRequestBody(APIType type, HttpRequestModel httpRequestModel) { APIType.graphql => getGraphQLBody(httpRequestModel), }; } +Map>? rowsToRequestMap(List? rows) { + if (rows == null) { + return null; + } + final Map> finalMap = {}; + for (var row in rows) { + final key = row.name.trim(); + if (key.isEmpty) continue; + final value = row.value.toString(); + if (finalMap.containsKey(key)) { + finalMap[key]!.add(value); + } else { + finalMap[key] = [value]; + } + } + return finalMap; +} + +List? requestMapToRows(Map>? requestMap) { + if (requestMap == null) { + return null; + } + final List finalRows = []; + requestMap.forEach((key, values) { + for (var value in values) { + finalRows.add(NameValueModel(name: key, value: value)); + } + }); + return finalRows; +} \ No newline at end of file diff --git a/packages/apidash_core/lib/utils/uri_utils.dart b/packages/apidash_core/lib/utils/uri_utils.dart index b111a2e08..901d7f73b 100644 --- a/packages/apidash_core/lib/utils/uri_utils.dart +++ b/packages/apidash_core/lib/utils/uri_utils.dart @@ -52,12 +52,14 @@ String stripUrlParams(String url) { uri = uri.removeFragment(); } - Map? queryParams = rowsToMap(requestParams); - if (queryParams != null && queryParams.isNotEmpty) { - if (uri.hasQuery) { - Map urlQueryParams = uri.queryParameters; - queryParams = mergeMaps(urlQueryParams, queryParams); - } + Map> queryParams = uri.queryParametersAll; + + Map>? requestQueryParams = rowsToRequestMap(requestParams); + if (requestQueryParams != null) { + queryParams = mergeMaps(queryParams, requestQueryParams, value: (v1, v2) => v1 + v2); +} + + if (queryParams.isNotEmpty) { uri = uri.replace(queryParameters: queryParams); } return (uri, null); diff --git a/test/models/http_request_model_test.dart b/test/models/http_request_model_test.dart index 78a520978..9cab2832e 100644 --- a/test/models/http_request_model_test.dart +++ b/test/models/http_request_model_test.dart @@ -33,7 +33,7 @@ void main() { 'User-Agent': 'Test Agent', 'Content-Type': 'application/json; charset=utf-8' }); - expect(httpRequestModel.paramsMap, {'size': '2', 'len': '3'}); + expect(httpRequestModel.paramsMap, {'size': ['2'], 'len': ['3']}); expect(httpRequestModel.enabledHeaders, const [ NameValueModel( name: 'Content-Type', value: 'application/json; charset=utf-8') @@ -44,7 +44,7 @@ void main() { ]); expect(httpRequestModel.enabledHeadersMap, {'Content-Type': 'application/json; charset=utf-8'}); - expect(httpRequestModel.enabledParamsMap, {'size': '2', 'len': '3'}); + expect(httpRequestModel.enabledParamsMap, {'size': ['2'], 'len': ['3']}); expect(httpRequestModel.hasContentTypeHeader, true); expect(httpRequestModel.hasFormDataContentType, false); diff --git a/test/widgets/table_request_test.dart b/test/widgets/table_request_test.dart index cc0e33242..0c94e03ee 100644 --- a/test/widgets/table_request_test.dart +++ b/test/widgets/table_request_test.dart @@ -1,4 +1,5 @@ import 'package:apidash/widgets/widgets.dart'; +import 'package:apidash_core/apidash_core.dart'; import 'package:data_table_2/data_table_2.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; @@ -6,10 +7,10 @@ import 'package:flutter_test/flutter_test.dart'; void main() { dataTableShowLogs = false; testWidgets('Testing RequestDataTable', (WidgetTester tester) async { - final Map sampleData = { - 'Key1': 'Value1', - 'Key2': 'Value2', - }; + final List sampleData = [ + const NameValueModel(name: 'key1', value: 'Value1'), + const NameValueModel(name: 'key2', value: 'value2'), + ]; await tester.pumpWidget( MaterialApp( @@ -22,12 +23,13 @@ void main() { ), ), ); + expect(find.byType(DataTable2), findsOneWidget); - expect(find.byType(ReadOnlyTextField), findsNWidgets(4)); + expect(find.byType(ReadOnlyTextField), findsNWidgets(4)); - expect(find.text('Key1'), findsOneWidget); + expect(find.text('key1'), findsOneWidget); expect(find.text('Value1'), findsOneWidget); - expect(find.text('Key2'), findsOneWidget); - expect(find.text('Value2'), findsOneWidget); + expect(find.text('key2'), findsOneWidget); + expect(find.text('value2'), findsOneWidget); }); -} +} \ No newline at end of file