diff --git a/generator/lib/src/generator.dart b/generator/lib/src/generator.dart index ff96d9bee..b4e438be6 100644 --- a/generator/lib/src/generator.dart +++ b/generator/lib/src/generator.dart @@ -984,7 +984,7 @@ You should create a new class to encapsulate the response. mapperVal = ''' (json)=> json is List ? json - .map<$genericTypeString>((i) => + .map<$genericTypeString>((i) => i as $genericTypeString ) .toList() @@ -1258,13 +1258,13 @@ You should create a new class to encapsulate the response. if (baseUrl == null || baseUrl.trim().isEmpty) { return dioBaseUrl; } - + final url = Uri.parse(baseUrl); - + if (url.isAbsolute) { return url.toString(); } - + return Uri.parse(dioBaseUrl).resolveUri(url).toString(); '''); }); @@ -1732,21 +1732,29 @@ ${bodyName.displayName} == null final contentType = r.peek('contentType')?.stringValue; if (isFileField) { + final keepFilePath = r.peek('keepFilePath')?.boolValue ?? false; final fileNameValue = r.peek('fileName')?.stringValue; final fileName = fileNameValue != null ? literalString(fileNameValue) : refer(p.displayName) .property('path.split(Platform.pathSeparator).last'); + final filePath = refer(p.displayName).property('path'); + final headers = keepFilePath + ? literalMap({ + 'original_file_path': literalList([filePath]) + }) + : literalMap({}); final uploadFileInfo = refer('$MultipartFile.fromFileSync').call([ - refer(p.displayName).property('path') + filePath ], { 'filename': fileName, if (contentType != null) 'contentType': refer('MediaType', 'package:http_parser/http_parser.dart') .property('parse') - .call([literal(contentType)]) + .call([literal(contentType)]), + 'headers': headers, }); final optionalFile = m.parameters @@ -1789,7 +1797,7 @@ ${bodyName.displayName} == null MultipartFile.fromBytes(${p.displayName}, filename:${literal(fileName)}, - $conType + $conType, )) ''') ]).statement; @@ -1823,7 +1831,7 @@ ${bodyName.displayName} == null '$fieldName', MultipartFile.fromBytes(i, filename:${literal(fileName)}, - $conType + $conType, ))) ''') ]).statement, @@ -1851,6 +1859,13 @@ ${bodyName.displayName} == null final conType = contentType == null ? '' : 'contentType: MediaType.parse(${literal(contentType)}),'; + final keepFilePath = r.peek('keepFilePath')?.boolValue ?? false; + final filePath = refer(p.displayName).property('path'); + final headers = keepFilePath + ? literalMap({ + 'original_file_path': [filePath] + }) + : '{}'; if (p.type.isNullable) { blocks.add(Code('if (${p.displayName} != null) {')); } @@ -1861,7 +1876,8 @@ ${bodyName.displayName} == null '$fieldName', MultipartFile.fromFileSync(i.path, filename: i.path.split(Platform.pathSeparator).last, - $conType + $conType, + headers: $headers, ))) ''') ]).statement, diff --git a/generator/pubspec.yaml b/generator/pubspec.yaml index 0d518a425..0f68c115e 100644 --- a/generator/pubspec.yaml +++ b/generator/pubspec.yaml @@ -17,7 +17,8 @@ dependencies: code_builder: ^4.4.0 dart_style: ^2.3.0 dio: ^5.0.0 - retrofit: ^4.0.1 + retrofit: ## update this dependency once a new version is released with keepOriginalPath change + path: ../retrofit source_gen: ^1.3.0 tuple: ^2.0.1 diff --git a/generator/test/src/generator_test_src.dart b/generator/test/src/generator_test_src.dart index 49803c94f..422ad415e 100644 --- a/generator/test/src/generator_test_src.dart +++ b/generator/test/src/generator_test_src.dart @@ -263,6 +263,9 @@ enum ImageType { icon, large } MultipartFile.fromFileSync( image.path, filename: image.path.split(Platform.pathSeparator).last, + headers: { + 'original_file_path': [image.path] + }, ), )); ''', @@ -271,7 +274,7 @@ enum ImageType { icon, large } @RestApi(baseUrl: 'https://httpbin.org/') abstract class FilePartTest { @POST('/profile') - Future setProfile(@Part() File image); + Future setProfile(@Part(keepFilePath: true) File image); } @ShouldGenerate( @@ -282,6 +285,7 @@ abstract class FilePartTest { MultipartFile.fromFileSync( image.path, filename: 'my_profile_image.jpg', + headers: {}, ), )); ''', @@ -320,7 +324,8 @@ abstract class FilePartWithMultipartListTest { @RestApi(baseUrl: 'https://httpbin.org/') abstract class FilePartWithNullableMultipartListTest { @POST('/profile') - Future setProfile(@Part() List? images); + Future setProfile( + @Part(keepFilePath: true) List? images); } @ShouldGenerate( @@ -331,6 +336,9 @@ abstract class FilePartWithNullableMultipartListTest { MultipartFile.fromFileSync( image.path, filename: image.path.split(Platform.pathSeparator).last, + headers: { + 'original_file_path': [image.path] + }, ), )); ''', @@ -339,7 +347,7 @@ abstract class FilePartWithNullableMultipartListTest { @RestApi(baseUrl: 'https://httpbin.org/') abstract class UploadFileInfoPartTest { @POST('/profile') - Future setProfile(@Part() File image); + Future setProfile(@Part(keepFilePath: true) File image); } @ShouldGenerate( @@ -940,6 +948,7 @@ abstract class TestHttpResponseArray { MultipartFile.fromFileSync( i.path, filename: i.path.split(Platform.pathSeparator).last, + headers: {}, )))); ''', contains: true, @@ -953,6 +962,7 @@ abstract class TestHttpResponseArray { MultipartFile.fromFileSync( i.path, filename: i.path.split(Platform.pathSeparator).last, + headers: {}, )))); } ''', @@ -966,6 +976,7 @@ abstract class TestHttpResponseArray { MultipartFile.fromFileSync( file.path, filename: file.path.split(Platform.pathSeparator).last, + headers: {}, ), )); } diff --git a/retrofit/lib/http.dart b/retrofit/lib/http.dart index 029525615..f656794c5 100644 --- a/retrofit/lib/http.dart +++ b/retrofit/lib/http.dart @@ -301,6 +301,7 @@ class Part { this.name, this.fileName, this.contentType, + this.keepFilePath = false, }); @Deprecated('future release') @@ -313,6 +314,9 @@ class Part { // To identify the content type of a file final String? contentType; + + /// If this field is a file, optionally specify whether to keep the file path for retrying requests + final bool? keepFilePath; } @immutable