Skip to content

Commit a3519b9

Browse files
committed
[dart][dart-dio] Improve support for file uploads
* add support for filenames in multipart requests by using `MultipartFile` from dio directly * add support for binary/file body data * fixes #6671 * fixes #9079
1 parent 696bcb3 commit a3519b9

File tree

9 files changed

+32
-34
lines changed

9 files changed

+32
-34
lines changed

.circleci/config.yml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,6 @@ jobs:
8282
- ~/.bundle
8383
- ~/.go_workspace
8484
- ~/.gradle
85-
- ~/.pub-cache
8685
- ~/.cache/bower
8786
- ".git"
8887
- ~/.stack

modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/DartDioNextClientCodegen.java

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ public class DartDioNextClientCodegen extends AbstractDartCodegen {
4646
public static final String SERIALIZATION_LIBRARY_BUILT_VALUE = "built_value";
4747
public static final String SERIALIZATION_LIBRARY_DEFAULT = SERIALIZATION_LIBRARY_BUILT_VALUE;
4848

49+
private static final String DIO_IMPORT = "package:dio/dio.dart";
4950
private static final String CLIENT_NAME = "clientName";
5051

5152
private String dateLibrary;
@@ -182,16 +183,16 @@ private void configureSerializationLibraryBuiltValue(String srcFolder) {
182183
typeMapping.put("List", "BuiltList");
183184
typeMapping.put("set", "BuiltSet");
184185
typeMapping.put("map", "BuiltMap");
185-
typeMapping.put("file", "Uint8List");
186-
typeMapping.put("binary", "Uint8List");
186+
typeMapping.put("file", "MultipartFile");
187+
typeMapping.put("binary", "MultipartFile");
187188
typeMapping.put("object", "JsonObject");
188189
typeMapping.put("AnyType", "JsonObject");
189190

190191
imports.put("BuiltList", "package:built_collection/built_collection.dart");
191192
imports.put("BuiltSet", "package:built_collection/built_collection.dart");
192193
imports.put("BuiltMap", "package:built_collection/built_collection.dart");
193194
imports.put("JsonObject", "package:built_value/json_object.dart");
194-
imports.put("Uint8List", "dart:typed_data");
195+
imports.put("MultipartFile", DIO_IMPORT);
195196
}
196197

197198
private void configureDateLibrary(String srcFolder) {
@@ -257,7 +258,7 @@ public Map<String, Object> postProcessModels(Map<String, Object> objs) {
257258
for (Object _mo : models) {
258259
Map<String, Object> mo = (Map<String, Object>) _mo;
259260
CodegenModel cm = (CodegenModel) mo.get("model");
260-
cm.imports = rewriteImports(cm.imports);
261+
cm.imports = rewriteImports(cm.imports, true);
261262
cm.vendorExtensions.put("x-has-vars", !cm.vars.isEmpty());
262263
}
263264
return objs;
@@ -302,7 +303,6 @@ private void appendBuiltValueCollection(StringBuilder sb, CodegenProperty proper
302303
sb.append(")]");
303304
}
304305

305-
306306
@Override
307307
public Map<String, Object> postProcessOperationsWithModels(Map<String, Object> objs, List<Object> allModels) {
308308
objs = super.postProcessOperationsWithModels(objs, allModels);
@@ -330,10 +330,6 @@ public Map<String, Object> postProcessOperationsWithModels(Map<String, Object> o
330330
}
331331

332332
for (CodegenParameter param : op.bodyParams) {
333-
if (param.baseType != null && param.baseType.equalsIgnoreCase("Uint8List") && isMultipart) {
334-
param.baseType = "MultipartFile";
335-
param.dataType = "MultipartFile";
336-
}
337333
if (param.isContainer) {
338334
final Map<String, Object> serializer = new HashMap<>();
339335
serializer.put("isArray", param.isArray);
@@ -348,7 +344,7 @@ public Map<String, Object> postProcessOperationsWithModels(Map<String, Object> o
348344
op.vendorExtensions.put("x-is-form", isForm);
349345
op.vendorExtensions.put("x-is-multipart", isMultipart);
350346

351-
resultImports.addAll(rewriteImports(op.imports));
347+
resultImports.addAll(rewriteImports(op.imports, false));
352348
if (op.getHasFormParams()) {
353349
resultImports.add("package:" + pubName + "/src/api_util.dart");
354350
}
@@ -369,11 +365,16 @@ public Map<String, Object> postProcessOperationsWithModels(Map<String, Object> o
369365
return objs;
370366
}
371367

372-
private Set<String> rewriteImports(Set<String> originalImports) {
368+
private Set<String> rewriteImports(Set<String> originalImports, boolean isModel) {
373369
Set<String> resultImports = Sets.newHashSet();
374370
for (String modelImport : originalImports) {
375371
if (imports.containsKey(modelImport)) {
376-
resultImports.add(imports.get(modelImport));
372+
String i = imports.get(modelImport);
373+
if (Objects.equals(i, DIO_IMPORT) && !isModel) {
374+
// Don't add imports to operations that are already imported
375+
continue;
376+
}
377+
resultImports.add(i);
377378
} else {
378379
resultImports.add("package:" + pubName + "/src/model/" + underscore(modelImport) + ".dart");
379380
}

modules/openapi-generator/src/main/resources/dart/libraries/dio/serialization/built_value/serialize.mustache

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
{{#hasFormParams}}
22
_bodyData = {{#isMultipart}}FormData.fromMap({{/isMultipart}}<String, dynamic>{
33
{{#formParams}}
4-
{{^required}}{{^isNullable}}if ({{{paramName}}} != null) {{/isNullable}}{{/required}}r'{{{baseName}}}': {{#isFile}}MultipartFile.fromBytes({{{paramName}}}, filename: r'{{{baseName}}}'){{/isFile}}{{^isFile}}encodeFormParameter(_serializers, {{{paramName}}}, const FullType({{^isContainer}}{{{baseType}}}{{/isContainer}}{{#isContainer}}Built{{#isMap}}Map{{/isMap}}{{#isArray}}{{#uniqueItems}}Set{{/uniqueItems}}{{^uniqueItems}}List{{/uniqueItems}}{{/isArray}}, [{{#isMap}}FullType(String), {{/isMap}}FullType({{{baseType}}})]{{/isContainer}})){{/isFile}},
4+
{{^required}}{{^isNullable}}if ({{{paramName}}} != null) {{/isNullable}}{{/required}}r'{{{baseName}}}': {{#isFile}}{{{paramName}}}{{/isFile}}{{^isFile}}encodeFormParameter(_serializers, {{{paramName}}}, const FullType({{^isContainer}}{{{baseType}}}{{/isContainer}}{{#isContainer}}Built{{#isMap}}Map{{/isMap}}{{#isArray}}{{#uniqueItems}}Set{{/uniqueItems}}{{^uniqueItems}}List{{/uniqueItems}}{{/isArray}}, [{{#isMap}}FullType(String), {{/isMap}}FullType({{{baseType}}})]{{/isContainer}})){{/isFile}},
55
{{/formParams}}
66
}{{#isMultipart}}){{/isMultipart}};
77
{{/hasFormParams}}
88
{{#bodyParam}}
99
{{#isPrimitiveType}}
10-
_bodyData = {{paramName}};
10+
_bodyData = {{paramName}}{{#isFile}}.finalize(){{/isFile}};
1111
{{/isPrimitiveType}}
1212
{{^isPrimitiveType}}
1313
{{#isContainer}}

samples/openapi3/client/petstore/dart-dio-next/petstore_client_lib_fake/doc/FakeApi.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -477,7 +477,7 @@ var int32 = 56; // int | None
477477
var int64 = 789; // int | None
478478
var float = 3.4; // double | None
479479
var string = string_example; // String | None
480-
var binary = BINARY_DATA_HERE; // Uint8List | None
480+
var binary = BINARY_DATA_HERE; // MultipartFile | None
481481
var date = 2013-10-20; // Date | None
482482
var dateTime = 2013-10-20T19:20:30+01:00; // DateTime | None
483483
var password = password_example; // String | None
@@ -503,7 +503,7 @@ Name | Type | Description | Notes
503503
**int64** | **int**| None | [optional]
504504
**float** | **double**| None | [optional]
505505
**string** | **String**| None | [optional]
506-
**binary** | **Uint8List**| None | [optional]
506+
**binary** | **MultipartFile**| None | [optional]
507507
**date** | **Date**| None | [optional]
508508
**dateTime** | **DateTime**| None | [optional]
509509
**password** | **String**| None | [optional]

samples/openapi3/client/petstore/dart-dio-next/petstore_client_lib_fake/doc/FormatTest.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ Name | Type | Description | Notes
1717
**decimal** | **double** | | [optional]
1818
**string** | **String** | | [optional]
1919
**byte** | **String** | |
20-
**binary** | [**Uint8List**](Uint8List.md) | | [optional]
20+
**binary** | [**MultipartFile**](MultipartFile.md) | | [optional]
2121
**date** | [**Date**](Date.md) | |
2222
**dateTime** | [**DateTime**](DateTime.md) | | [optional]
2323
**uuid** | **String** | | [optional]

samples/openapi3/client/petstore/dart-dio-next/petstore_client_lib_fake/doc/PetApi.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -345,7 +345,7 @@ import 'package:openapi/api.dart';
345345
var api_instance = new PetApi();
346346
var petId = 789; // int | ID of pet to update
347347
var additionalMetadata = additionalMetadata_example; // String | Additional data to pass to server
348-
var file = BINARY_DATA_HERE; // Uint8List | file to upload
348+
var file = BINARY_DATA_HERE; // MultipartFile | file to upload
349349
350350
try {
351351
var result = api_instance.uploadFile(petId, additionalMetadata, file);
@@ -361,7 +361,7 @@ Name | Type | Description | Notes
361361
------------- | ------------- | ------------- | -------------
362362
**petId** | **int**| ID of pet to update |
363363
**additionalMetadata** | **String**| Additional data to pass to server | [optional]
364-
**file** | **Uint8List**| file to upload | [optional]
364+
**file** | **MultipartFile**| file to upload | [optional]
365365

366366
### Return type
367367

@@ -391,7 +391,7 @@ import 'package:openapi/api.dart';
391391
392392
var api_instance = new PetApi();
393393
var petId = 789; // int | ID of pet to update
394-
var requiredFile = BINARY_DATA_HERE; // Uint8List | file to upload
394+
var requiredFile = BINARY_DATA_HERE; // MultipartFile | file to upload
395395
var additionalMetadata = additionalMetadata_example; // String | Additional data to pass to server
396396
397397
try {
@@ -407,7 +407,7 @@ try {
407407
Name | Type | Description | Notes
408408
------------- | ------------- | ------------- | -------------
409409
**petId** | **int**| ID of pet to update |
410-
**requiredFile** | **Uint8List**| file to upload |
410+
**requiredFile** | **MultipartFile**| file to upload |
411411
**additionalMetadata** | **String**| Additional data to pass to server | [optional]
412412

413413
### Return type

samples/openapi3/client/petstore/dart-dio-next/petstore_client_lib_fake/lib/src/api/fake_api.dart

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import 'dart:async';
77
import 'package:built_value/serializer.dart';
88
import 'package:dio/dio.dart';
99

10-
import 'dart:typed_data';
1110
import 'package:built_collection/built_collection.dart';
1211
import 'package:openapi/src/api_util.dart';
1312
import 'package:openapi/src/model/date.dart';
@@ -826,7 +825,7 @@ class FakeApi {
826825
int? int64,
827826
double? float,
828827
String? string,
829-
Uint8List? binary,
828+
MultipartFile? binary,
830829
Date? date,
831830
DateTime? dateTime,
832831
String? password,
@@ -875,7 +874,7 @@ class FakeApi {
875874
if (string != null) r'string': encodeFormParameter(_serializers, string, const FullType(String)),
876875
r'pattern_without_delimiter': encodeFormParameter(_serializers, patternWithoutDelimiter, const FullType(String)),
877876
r'byte': encodeFormParameter(_serializers, byte, const FullType(String)),
878-
if (binary != null) r'binary': MultipartFile.fromBytes(binary, filename: r'binary'),
877+
if (binary != null) r'binary': binary,
879878
if (date != null) r'date': encodeFormParameter(_serializers, date, const FullType(Date)),
880879
if (dateTime != null) r'dateTime': encodeFormParameter(_serializers, dateTime, const FullType(DateTime)),
881880
if (password != null) r'password': encodeFormParameter(_serializers, password, const FullType(String)),

samples/openapi3/client/petstore/dart-dio-next/petstore_client_lib_fake/lib/src/api/pet_api.dart

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import 'dart:async';
77
import 'package:built_value/serializer.dart';
88
import 'package:dio/dio.dart';
99

10-
import 'dart:typed_data';
1110
import 'package:built_collection/built_collection.dart';
1211
import 'package:openapi/src/api_util.dart';
1312
import 'package:openapi/src/model/api_response.dart';
@@ -513,7 +512,7 @@ class PetApi {
513512
Future<Response<ApiResponse>> uploadFile({
514513
required int petId,
515514
String? additionalMetadata,
516-
Uint8List? file,
515+
MultipartFile? file,
517516
CancelToken? cancelToken,
518517
Map<String, dynamic>? headers,
519518
Map<String, dynamic>? extra,
@@ -550,7 +549,7 @@ class PetApi {
550549
try {
551550
_bodyData = FormData.fromMap(<String, dynamic>{
552551
if (additionalMetadata != null) r'additionalMetadata': encodeFormParameter(_serializers, additionalMetadata, const FullType(String)),
553-
if (file != null) r'file': MultipartFile.fromBytes(file, filename: r'file'),
552+
if (file != null) r'file': file,
554553
});
555554

556555
} catch(error) {
@@ -610,7 +609,7 @@ class PetApi {
610609
///
611610
Future<Response<ApiResponse>> uploadFileWithRequiredFile({
612611
required int petId,
613-
required Uint8List requiredFile,
612+
required MultipartFile requiredFile,
614613
String? additionalMetadata,
615614
CancelToken? cancelToken,
616615
Map<String, dynamic>? headers,
@@ -648,7 +647,7 @@ class PetApi {
648647
try {
649648
_bodyData = FormData.fromMap(<String, dynamic>{
650649
if (additionalMetadata != null) r'additionalMetadata': encodeFormParameter(_serializers, additionalMetadata, const FullType(String)),
651-
r'requiredFile': MultipartFile.fromBytes(requiredFile, filename: r'requiredFile'),
650+
r'requiredFile': requiredFile,
652651
});
653652

654653
} catch(error) {

samples/openapi3/client/petstore/dart-dio-next/petstore_client_lib_fake/lib/src/model/format_test.dart

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22
// AUTO-GENERATED FILE, DO NOT MODIFY!
33
//
44

5-
import 'dart:typed_data';
65
import 'package:openapi/src/model/date.dart';
6+
import 'package:dio/dio.dart';
77
import 'package:built_value/built_value.dart';
88
import 'package:built_value/serializer.dart';
99

@@ -40,7 +40,7 @@ abstract class FormatTest implements Built<FormatTest, FormatTestBuilder> {
4040
String get byte;
4141

4242
@BuiltValueField(wireName: r'binary')
43-
Uint8List? get binary;
43+
MultipartFile? get binary;
4444

4545
@BuiltValueField(wireName: r'date')
4646
Date get date;
@@ -137,7 +137,7 @@ class _$FormatTestSerializer implements StructuredSerializer<FormatTest> {
137137
result
138138
..add(r'binary')
139139
..add(serializers.serialize(object.binary,
140-
specifiedType: const FullType(Uint8List)));
140+
specifiedType: const FullType(MultipartFile)));
141141
}
142142
result
143143
..add(r'date')
@@ -223,7 +223,7 @@ class _$FormatTestSerializer implements StructuredSerializer<FormatTest> {
223223
break;
224224
case r'binary':
225225
result.binary = serializers.deserialize(value,
226-
specifiedType: const FullType(Uint8List)) as Uint8List;
226+
specifiedType: const FullType(MultipartFile)) as MultipartFile;
227227
break;
228228
case r'date':
229229
result.date = serializers.deserialize(value,

0 commit comments

Comments
 (0)