diff --git a/modules/openapi-generator/src/main/resources/dart2/api_client.mustache b/modules/openapi-generator/src/main/resources/dart2/api_client.mustache index 6fab896fa79..bb6a4565fc7 100644 --- a/modules/openapi-generator/src/main/resources/dart2/api_client.mustache +++ b/modules/openapi-generator/src/main/resources/dart2/api_client.mustache @@ -1,12 +1,5 @@ {{>header}} {{>part_of}} -class QueryParam { - QueryParam(this.name, this.value); - - String name; - String value; -} - class ApiClient { ApiClient({this.basePath = '{{{basePath}}}'}) { {{#hasAuthMethods}} @@ -88,11 +81,13 @@ class ApiClient { headerParams.addAll(_defaultHeaderMap); - final ps = queryParams - .where((p) => p.value != null) - .map((p) => '${p.name}=${Uri.encodeQueryComponent(p.value)}'); + final urlEncodedQueryParams = queryParams + .where((param) => param.value != null) + .map((param) => '$param'); - final queryString = ps.isNotEmpty ? '?' + ps.join('&') : ''; + final queryString = urlEncodedQueryParams.isNotEmpty + ? '?${urlEncodedQueryParams.join('&')}' + : ''; final url = '$basePath$path$queryString'; @@ -100,41 +95,61 @@ class ApiClient { headerParams['Content-Type'] = nullableContentType; } - if (body is MultipartRequest) { - final request = MultipartRequest(method, Uri.parse(url)); - request.fields.addAll(body.fields); - request.files.addAll(body.files); - request.headers.addAll(body.headers); - request.headers.addAll(headerParams); - final response = await _client.send(request); - return Response.fromStream(response); - } - - final msgBody = nullableContentType == 'application/x-www-form-urlencoded' - ? formParams - : serialize(body); - final nullableHeaderParams = headerParams.isEmpty ? null : headerParams; - try { + // Special case for uploading a single file which isn’t a 'multipart/form-data'. + if ( + body is MultipartFile && (nullableContentType == null || + !nullableContentType.toLowerCase().startsWith('multipart/form-data')) + ) { + final request = StreamedRequest(method, Uri.parse(url)); + request.headers.addAll(headerParams); + request.contentLength = body.length; + body.finalize().listen( + request.sink.add, + onDone: request.sink.close, + onError: (error, trace) => request.sink.close(), + cancelOnError: true, + ); + final response = await _client.send(request); + return Response.fromStream(response); + } + + if (body is MultipartRequest) { + final request = MultipartRequest(method, Uri.parse(url)); + request.fields.addAll(body.fields); + request.files.addAll(body.files); + request.headers.addAll(body.headers); + request.headers.addAll(headerParams); + final response = await _client.send(request); + return Response.fromStream(response); + } + + final msgBody = nullableContentType == 'application/x-www-form-urlencoded' + ? formParams + : serialize(body); + final nullableHeaderParams = headerParams.isEmpty ? null : headerParams; + switch(method) { - case 'POST': return await _client.post(url, headers: nullableHeaderParams, body: msgBody); - case 'PUT': return await _client.put(url, headers: nullableHeaderParams, body: msgBody); - case 'DELETE': return await _client.delete(url, headers: nullableHeaderParams); - case 'PATCH': return await _client.patch(url, headers: nullableHeaderParams, body: msgBody); - case 'HEAD': return await _client.head(url, headers: nullableHeaderParams); - case 'GET': return await _client.get(url, headers: nullableHeaderParams); + case 'POST': return await _client.post(url, headers: nullableHeaderParams, body: msgBody,); + case 'PUT': return await _client.put(url, headers: nullableHeaderParams, body: msgBody,); + case 'DELETE': return await _client.delete(url, headers: nullableHeaderParams,); + case 'PATCH': return await _client.patch(url, headers: nullableHeaderParams, body: msgBody,); + case 'HEAD': return await _client.head(url, headers: nullableHeaderParams,); + case 'GET': return await _client.get(url, headers: nullableHeaderParams,); } } on SocketException catch (e, trace) { - throw ApiException.withInner(HttpStatus.badRequest, 'Socket operation failed: $method $path', e, trace); + throw ApiException.withInner(HttpStatus.badRequest, 'Socket operation failed: $method $path', e, trace,); } on TlsException catch (e, trace) { - throw ApiException.withInner(HttpStatus.badRequest, 'TLS/SSL communication failed: $method $path', e, trace); + throw ApiException.withInner(HttpStatus.badRequest, 'TLS/SSL communication failed: $method $path', e, trace,); } on IOException catch (e, trace) { - throw ApiException.withInner(HttpStatus.badRequest, 'I/O operation failed: $method $path', e, trace); + throw ApiException.withInner(HttpStatus.badRequest, 'I/O operation failed: $method $path', e, trace,); + } on ClientException catch (e, trace) { + throw ApiException.withInner(HttpStatus.badRequest, 'HTTP connection failed: $method $path', e, trace,); } on Exception catch (e, trace) { - throw ApiException.withInner(HttpStatus.badRequest, 'Exception occurred: $method $path', e, trace); + throw ApiException.withInner(HttpStatus.badRequest, 'Exception occurred: $method $path', e, trace,); } - throw ApiException(HttpStatus.badRequest, 'Invalid HTTP operation: $method $path'); + throw ApiException(HttpStatus.badRequest, 'Invalid HTTP operation: $method $path',); } dynamic _deserialize(dynamic value, String targetType, {bool growable}) { @@ -182,9 +197,9 @@ class ApiClient { break; } } on Exception catch (e, stack) { - throw ApiException.withInner(HttpStatus.internalServerError, 'Exception during deserialization.', e, stack); + throw ApiException.withInner(HttpStatus.internalServerError, 'Exception during deserialization.', e, stack,); } - throw ApiException(HttpStatus.internalServerError, 'Could not find a suitable class for deserialization'); + throw ApiException(HttpStatus.internalServerError, 'Could not find a suitable class for deserialization',); } /// Update query and header parameters based on authentication settings. diff --git a/modules/openapi-generator/src/main/resources/dart2/api_helper.mustache b/modules/openapi-generator/src/main/resources/dart2/api_helper.mustache index e851e731433..4ca7af11651 100644 --- a/modules/openapi-generator/src/main/resources/dart2/api_helper.mustache +++ b/modules/openapi-generator/src/main/resources/dart2/api_helper.mustache @@ -1,5 +1,15 @@ {{>header}} {{>part_of}} +class QueryParam { + const QueryParam(this.name, this.value); + + final String name; + final String value; + + @override + String toString() => '${Uri.encodeQueryComponent(name)}=${Uri.encodeQueryComponent(value)}'; +} + // Ported from the Java version. Iterable _convertParametersForCollectionFormat( String collectionFormat, diff --git a/samples/client/petstore/dart2/petstore_client_lib/lib/api_client.dart b/samples/client/petstore/dart2/petstore_client_lib/lib/api_client.dart index af9d4ec7a69..b65252d99d5 100644 --- a/samples/client/petstore/dart2/petstore_client_lib/lib/api_client.dart +++ b/samples/client/petstore/dart2/petstore_client_lib/lib/api_client.dart @@ -9,13 +9,6 @@ part of openapi.api; -class QueryParam { - QueryParam(this.name, this.value); - - String name; - String value; -} - class ApiClient { ApiClient({this.basePath = 'http://petstore.swagger.io/v2'}) { // Setup authentications (key: authentication name, value: authentication). @@ -81,11 +74,13 @@ class ApiClient { headerParams.addAll(_defaultHeaderMap); - final ps = queryParams - .where((p) => p.value != null) - .map((p) => '${p.name}=${Uri.encodeQueryComponent(p.value)}'); + final urlEncodedQueryParams = queryParams + .where((param) => param.value != null) + .map((param) => '$param'); - final queryString = ps.isNotEmpty ? '?' + ps.join('&') : ''; + final queryString = urlEncodedQueryParams.isNotEmpty + ? '?${urlEncodedQueryParams.join('&')}' + : ''; final url = '$basePath$path$queryString'; @@ -93,41 +88,61 @@ class ApiClient { headerParams['Content-Type'] = nullableContentType; } - if (body is MultipartRequest) { - final request = MultipartRequest(method, Uri.parse(url)); - request.fields.addAll(body.fields); - request.files.addAll(body.files); - request.headers.addAll(body.headers); - request.headers.addAll(headerParams); - final response = await _client.send(request); - return Response.fromStream(response); - } - - final msgBody = nullableContentType == 'application/x-www-form-urlencoded' - ? formParams - : serialize(body); - final nullableHeaderParams = headerParams.isEmpty ? null : headerParams; - try { + // Special case for uploading a single file which isn’t a 'multipart/form-data'. + if ( + body is MultipartFile && (nullableContentType == null || + !nullableContentType.toLowerCase().startsWith('multipart/form-data')) + ) { + final request = StreamedRequest(method, Uri.parse(url)); + request.headers.addAll(headerParams); + request.contentLength = body.length; + body.finalize().listen( + request.sink.add, + onDone: request.sink.close, + onError: (error, trace) => request.sink.close(), + cancelOnError: true, + ); + final response = await _client.send(request); + return Response.fromStream(response); + } + + if (body is MultipartRequest) { + final request = MultipartRequest(method, Uri.parse(url)); + request.fields.addAll(body.fields); + request.files.addAll(body.files); + request.headers.addAll(body.headers); + request.headers.addAll(headerParams); + final response = await _client.send(request); + return Response.fromStream(response); + } + + final msgBody = nullableContentType == 'application/x-www-form-urlencoded' + ? formParams + : serialize(body); + final nullableHeaderParams = headerParams.isEmpty ? null : headerParams; + switch(method) { - case 'POST': return await _client.post(url, headers: nullableHeaderParams, body: msgBody); - case 'PUT': return await _client.put(url, headers: nullableHeaderParams, body: msgBody); - case 'DELETE': return await _client.delete(url, headers: nullableHeaderParams); - case 'PATCH': return await _client.patch(url, headers: nullableHeaderParams, body: msgBody); - case 'HEAD': return await _client.head(url, headers: nullableHeaderParams); - case 'GET': return await _client.get(url, headers: nullableHeaderParams); + case 'POST': return await _client.post(url, headers: nullableHeaderParams, body: msgBody,); + case 'PUT': return await _client.put(url, headers: nullableHeaderParams, body: msgBody,); + case 'DELETE': return await _client.delete(url, headers: nullableHeaderParams,); + case 'PATCH': return await _client.patch(url, headers: nullableHeaderParams, body: msgBody,); + case 'HEAD': return await _client.head(url, headers: nullableHeaderParams,); + case 'GET': return await _client.get(url, headers: nullableHeaderParams,); } } on SocketException catch (e, trace) { - throw ApiException.withInner(HttpStatus.badRequest, 'Socket operation failed: $method $path', e, trace); + throw ApiException.withInner(HttpStatus.badRequest, 'Socket operation failed: $method $path', e, trace,); } on TlsException catch (e, trace) { - throw ApiException.withInner(HttpStatus.badRequest, 'TLS/SSL communication failed: $method $path', e, trace); + throw ApiException.withInner(HttpStatus.badRequest, 'TLS/SSL communication failed: $method $path', e, trace,); } on IOException catch (e, trace) { - throw ApiException.withInner(HttpStatus.badRequest, 'I/O operation failed: $method $path', e, trace); + throw ApiException.withInner(HttpStatus.badRequest, 'I/O operation failed: $method $path', e, trace,); + } on ClientException catch (e, trace) { + throw ApiException.withInner(HttpStatus.badRequest, 'HTTP connection failed: $method $path', e, trace,); } on Exception catch (e, trace) { - throw ApiException.withInner(HttpStatus.badRequest, 'Exception occurred: $method $path', e, trace); + throw ApiException.withInner(HttpStatus.badRequest, 'Exception occurred: $method $path', e, trace,); } - throw ApiException(HttpStatus.badRequest, 'Invalid HTTP operation: $method $path'); + throw ApiException(HttpStatus.badRequest, 'Invalid HTTP operation: $method $path',); } dynamic _deserialize(dynamic value, String targetType, {bool growable}) { @@ -176,9 +191,9 @@ class ApiClient { break; } } on Exception catch (e, stack) { - throw ApiException.withInner(HttpStatus.internalServerError, 'Exception during deserialization.', e, stack); + throw ApiException.withInner(HttpStatus.internalServerError, 'Exception during deserialization.', e, stack,); } - throw ApiException(HttpStatus.internalServerError, 'Could not find a suitable class for deserialization'); + throw ApiException(HttpStatus.internalServerError, 'Could not find a suitable class for deserialization',); } /// Update query and header parameters based on authentication settings. diff --git a/samples/client/petstore/dart2/petstore_client_lib/lib/api_helper.dart b/samples/client/petstore/dart2/petstore_client_lib/lib/api_helper.dart index 5ae7b8d6de7..141f4a7f5b4 100644 --- a/samples/client/petstore/dart2/petstore_client_lib/lib/api_helper.dart +++ b/samples/client/petstore/dart2/petstore_client_lib/lib/api_helper.dart @@ -9,6 +9,16 @@ part of openapi.api; +class QueryParam { + const QueryParam(this.name, this.value); + + final String name; + final String value; + + @override + String toString() => '${Uri.encodeQueryComponent(name)}=${Uri.encodeQueryComponent(value)}'; +} + // Ported from the Java version. Iterable _convertParametersForCollectionFormat( String collectionFormat,