Skip to content

Commit f33ff15

Browse files
committed
[Dart] Add Uint8List support to Dart generator (#12161)
* Adds Uint8List as a valid return type for type: string format: binary definitions * Adds support for using bodyBytes instead of body for deserializing response data
1 parent 7e87b5d commit f33ff15

File tree

4 files changed

+20
-17
lines changed

4 files changed

+20
-17
lines changed

modules/openapi-generator/src/main/resources/dart2/api.mustache

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@ class {{{classname}}} {
164164
Future<{{#returnType}}{{{.}}}?{{/returnType}}{{^returnType}}void{{/returnType}}> {{{nickname}}}({{#allParams}}{{#required}}{{{dataType}}} {{{paramName}}},{{^-last}} {{/-last}}{{/required}}{{/allParams}}{{#hasOptionalParams}}{ {{#allParams}}{{^required}}{{{dataType}}}? {{{paramName}}},{{^-last}} {{/-last}}{{/required}}{{/allParams}} }{{/hasOptionalParams}}) async {
165165
final response = await {{{nickname}}}WithHttpInfo({{#allParams}}{{#required}}{{{paramName}}},{{^-last}} {{/-last}}{{/required}}{{/allParams}}{{#hasOptionalParams}} {{#allParams}}{{^required}}{{{paramName}}}: {{{paramName}}},{{^-last}} {{/-last}}{{/required}}{{/allParams}} {{/hasOptionalParams}});
166166
if (response.statusCode >= HttpStatus.badRequest) {
167-
throw ApiException(response.statusCode, await _decodeBodyBytes(response));
167+
throw ApiException(response.statusCode, decodeError(await response.bodyBytes));
168168
}
169169
{{#returnType}}
170170
// When a remote server returns no body with a status of 204, we shall not decode it.
@@ -173,17 +173,16 @@ class {{{classname}}} {
173173
if (response.body.isNotEmpty && response.statusCode != HttpStatus.noContent) {
174174
{{#native_serialization}}
175175
{{#isArray}}
176-
final responseBody = await _decodeBodyBytes(response);
177-
return (await apiClient.deserializeAsync(responseBody, '{{{returnType}}}') as List)
176+
return (await apiClient.deserializeAsync(response.bodyBytes, '{{{returnType}}}') as List)
178177
.cast<{{{returnBaseType}}}>()
179178
.{{#uniqueItems}}toSet(){{/uniqueItems}}{{^uniqueItems}}toList(){{/uniqueItems}};
180179
{{/isArray}}
181180
{{^isArray}}
182181
{{#isMap}}
183-
return {{{returnType}}}.from(await apiClient.deserializeAsync(await _decodeBodyBytes(response), '{{{returnType}}}'),);
182+
return {{{returnType}}}.from(await apiClient.deserializeAsync(response.bodyBytes, '{{{returnType}}}'),);
184183
{{/isMap}}
185184
{{^isMap}}
186-
return await apiClient.deserializeAsync(await _decodeBodyBytes(response), '{{{returnType}}}',) as {{{returnType}}};
185+
return await apiClient.deserializeAsync(response.bodyBytes, '{{{returnType}}}',) as {{{returnType}}};
187186
{{/isMap}}{{/isArray}}{{/native_serialization}}
188187
}
189188
return null;

modules/openapi-generator/src/main/resources/dart2/api_client.mustache

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -134,19 +134,25 @@ class ApiClient {
134134
}
135135
{{#native_serialization}}
136136
137-
Future<dynamic> deserializeAsync(String json, String targetType, {bool growable = false,}) async =>
137+
Future<dynamic> deserializeAsync(Uint8List responseBytes, String targetType, {bool growable = false,}) async =>
138138
// ignore: deprecated_member_use_from_same_package
139-
deserialize(json, targetType, growable: growable);
139+
deserialize(responseBytes, targetType, growable: growable);
140140
141141
@Deprecated('Scheduled for removal in OpenAPI Generator 6.x. Use deserializeAsync() instead.')
142-
dynamic deserialize(String json, String targetType, {bool growable = false,}) {
142+
dynamic deserialize(Uint8List responseBytes, String targetType, {bool growable = false,}) {
143143
// Remove all spaces. Necessary for regular expressions as well.
144144
targetType = targetType.replaceAll(' ', ''); // ignore: parameter_assignments
145145
146+
// if the expected target type is a byte-array, then just return the response bytes as-is
147+
if (targetType == 'Uint8List') {
148+
return responseBytes;
149+
}
150+
151+
final decodedString = const Utf8Decoder().convert(responseBytes);
146152
// If the expected target type is String, nothing to do...
147153
return targetType == 'String'
148-
? json
149-
: _deserialize(jsonDecode(json), targetType, growable: growable);
154+
? decodedString
155+
: _deserialize(jsonDecode(decodedString), targetType, growable: growable);
150156
}
151157
{{/native_serialization}}
152158

modules/openapi-generator/src/main/resources/dart2/api_helper.mustache

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -57,13 +57,10 @@ String parameterToString(dynamic value) {
5757
return value.toString();
5858
}
5959

60-
/// Returns the decoded body as UTF-8 if the given headers indicate an 'application/json'
61-
/// content type. Otherwise, returns the decoded body as decoded by dart:http package.
62-
Future<String> _decodeBodyBytes(Response response) async {
63-
final contentType = response.headers['content-type'];
64-
return contentType != null && contentType.toLowerCase().startsWith('application/json')
65-
? response.bodyBytes.isEmpty ? '' : utf8.decode(response.bodyBytes)
66-
: response.body;
60+
/// Decodes the response body for error reporting purposes.
61+
/// Decodes as UTF-8 but allows for malformed bytes to avoid crashing.
62+
String decodeError(Uint8List responseBytes) {
63+
return const Utf8Decoder(allowMalformed: true).convert(responseBytes);
6764
}
6865

6966
/// Returns a valid [T] value found at the specified Map [key], null otherwise.

modules/openapi-generator/src/main/resources/dart2/apilib.mustache

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import 'dart:async';
55
import 'dart:convert';
66
import 'dart:io';
7+
import 'dart:typed_data';
78

89
import 'package:http/http.dart';
910
import 'package:intl/intl.dart';

0 commit comments

Comments
 (0)