openapi-generator
openapi-generator copied to clipboard
[BUG] [DART] Dart Generator does not generate Multipart properly. Sends an empty object instead of file
Bug Report Checklist
- [x] Have you provided a full/minimal spec to reproduce the issue? Started from 6.0.0 (5.4.0 worked perfectly)
- [x] Have you validated the input using an OpenAPI validator (example)?
- [ ] Have you tested with the latest master to confirm the issue still exists?
- [x] Have you searched for related issues/PRs?
- [x] What's the actual output vs expected output?
Description
The Dart generator does not generate multipart properly. It sends an empty object instead of a multipart file provided.
It appears only with such configuration: dart-dio
, json_serializable
and timemachine
.
If you use just a dart
generator instead of dart-dio
it generates it properly.
Here is an example of faulty outputs
Future<Response<UploadProfessionalImage201Response>> uploadProfessionalImage({
required String professionalId,
MultipartFile? image,
CancelToken? cancelToken,
Map<String, dynamic>? headers,
Map<String, dynamic>? extra,
ValidateStatus? validateStatus,
ProgressCallback? onSendProgress,
ProgressCallback? onReceiveProgress,
}) async {
final _path = r'/images/professionals/{professionalId}/'.replaceAll('{' r'professionalId' '}', professionalId.toString());
final _options = Options(
method: r'POST',
headers: <String, dynamic>{
...?headers,
},
extra: <String, dynamic>{
'secure': <Map<String, String>>[
{
'type': 'apiKey',
'name': 'BearerToken',
'keyName': 'Authorization',
'where': 'header',
},
],
...?extra,
},
contentType: 'multipart/form-data',
validateStatus: validateStatus,
);
dynamic _bodyData;
try {
} catch(error, stackTrace) {
throw DioError(
requestOptions: _options.compose(
_dio.options,
_path,
),
type: DioErrorType.other,
error: error,
)..stackTrace = stackTrace;
}
final _response = await _dio.request<Object>(
_path,
data: _bodyData,
options: _options,
cancelToken: cancelToken,
onSendProgress: onSendProgress,
onReceiveProgress: onReceiveProgress,
);
UploadProfessionalImage201Response _responseData;
try {
_responseData = deserialize<UploadProfessionalImage201Response, UploadProfessionalImage201Response>(_response.data!, 'UploadProfessionalImage201Response', growable: true);
} catch (error, stackTrace) {
throw DioError(
requestOptions: _response.requestOptions,
response: _response,
type: DioErrorType.other,
error: error,
)..stackTrace = stackTrace;
}
return Response<UploadProfessionalImage201Response>(
data: _responseData,
headers: _response.headers,
isRedirect: _response.isRedirect,
requestOptions: _response.requestOptions,
redirects: _response.redirects,
statusCode: _response.statusCode,
statusMessage: _response.statusMessage,
extra: _response.extra,
);
}
As you can see _bodyData
is completely empty.
This is a problem because it makes this API call completely useless and swapping to standard dart
generator would mean a lot of refactoring and losing features for us.
openapi-generator version
From 6.0.0 and onward
5.4.0 works fine
OpenAPI declaration file content or url
"/images/professionals/{professionalId}/": {
"post": {
"security": [
{
"BearerToken": []
}
],
"description": "Upload image for professional (profile image)",
"consumes": [
"multipart/form-data"
],
"tags": [
"Image"
],
"operationId": "UploadProfessionalImage",
"parameters": [
{
"type": "file",
"description": "Image file",
"name": "image",
"in": "formData",
"required": false
},
{
"type": "string",
"description": "Professional ID",
"name": "professionalId",
"in": "path",
"required": true
}
],
"responses": {
"201": {
"description": "Created",
"schema": {
"allOf": [
{
"type": "object"
},
{
"type": "object",
"properties": {
"data": {
"$ref": "#/definitions/dto.Image"
}
}
}
]
}
},
"default": {
"description": "",
"schema": {
"allOf": [
{
"type": "object"
},
{
"type": "object",
"properties": {
"error": {
"$ref": "#/definitions/errs.E"
}
}
}
]
}
}
}
}
},
Generation Details
openapi-generator-cli generate -i swagger.json -g dart-dio -o ./ -p dateLibrary=timemachine,pubLibrary=eliva.api,pubName=project_api,serializationLibrary=json_serializable
Steps to reproduce
Just generate using the command and the faulty code appears
Suggest a fix
No idea unfortunatelly
We are also facing this issue! Very annoying!
We are facing this issue with version 6.5.0
Here is an sample of swagger.json
"requestBody": { "content": { "multipart/form-data": { "schema": { "required": [ "files" ], "type": "object", "properties": { "files": { "type": "array", "items": { "type": "string", "format": "binary" } } } }, "encoding": { "files": { "style": "form" } } } } },
And the workaround we implemented on generated file
FormData _bodyData = FormData.fromMap( <String, List<MultipartFile>>{"files": files}); // MANUALLY ADDED !
@jaumard (2018/09) @josh-burton (2019/12) @amondnet (2019/12) @sbu-WBT (2020/12) @kuhnroyal (2020/12) @agilob (2020/12) @ahmednfwela (2021/08)
@Yegorisa You seem to be using OpenAPI 2.0 - please provide a full spec that reproduces the issue.
@francois-robert I generated your snippet on master and got the following result, which look correct on the first glance:
/// fooPost
///
///
/// Parameters:
/// * [files]
/// * [cancelToken] - A [CancelToken] that can be used to cancel the operation
/// * [headers] - Can be used to add additional headers to the request
/// * [extras] - Can be used to add flags to the request
/// * [validateStatus] - A [ValidateStatus] callback that can be used to determine request success based on the HTTP status of the response
/// * [onSendProgress] - A [ProgressCallback] that can be used to get the send progress
/// * [onReceiveProgress] - A [ProgressCallback] that can be used to get the receive progress
///
/// Returns a [Future]
/// Throws [DioException] if API call or serialization fails
Future<Response<void>> fooPost({
required BuiltList<MultipartFile> files,
CancelToken? cancelToken,
Map<String, dynamic>? headers,
Map<String, dynamic>? extra,
ValidateStatus? validateStatus,
ProgressCallback? onSendProgress,
ProgressCallback? onReceiveProgress,
}) async {
final _path = r'/foo';
final _options = Options(
method: r'POST',
headers: <String, dynamic>{
...?headers,
},
extra: <String, dynamic>{
'secure': <Map<String, String>>[],
...?extra,
},
contentType: 'multipart/form-data',
validateStatus: validateStatus,
);
dynamic _bodyData;
try {
_bodyData = FormData.fromMap(<String, dynamic>{
r'files': files.toList(),
});
} catch(error, stackTrace) {
throw DioException(
requestOptions: _options.compose(
_dio.options,
_path,
),
type: DioExceptionType.unknown,
error: error,
stackTrace: stackTrace,
);
}
final _response = await _dio.request<Object>(
_path,
data: _bodyData,
options: _options,
cancelToken: cancelToken,
onSendProgress: onSendProgress,
onReceiveProgress: onReceiveProgress,
);
return _response;
}
@kuhnroyal Thanks for your answer. It seems that it is working with default parameters but when using "--additional-properties=serializationLibrary=json_serializable" it does generate _bodyData at all.
Ah I see, thanks - will take a look.
note that this is fixed in DartNext generator
Nice! Still might fix it for 7.0.0 in dart-dio. Will see if I find the time.
Any status on this? Or is this being dropped in favour of DartNext (Can't seem to find what 'DartNext' is though 😅)?
Can't seem to find what 'DartNext' is though 😅
It's this PR https://github.com/OpenAPITools/openapi-generator/pull/15485
It's this PR https://github.com/OpenAPITools/openapi-generator/pull/15485
Ah thanks! searched for DartNext, rather than dart-next... 🙃
Also thanks for the quick response 😄
@kuhnroyal Thanks for your answer. It seems that it is working with default parameters but when using "--additional-properties=serializationLibrary=json_serializable" it does generate _bodyData at all.
Hi, is this solved? Still happened to me, using docker image. Working fine if remove the additional-properties.