Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 8 additions & 21 deletions lib/src/code_generators/swagger_requests_generator.dart
Original file line number Diff line number Diff line change
Expand Up @@ -779,24 +779,6 @@ class SwaggerRequestsGenerator extends SwaggerGeneratorBase {
schema = root.allSchemas[schema?.ref.getUnformattedRef()];
}

// in case a scheme for the request is defined, we use only one param const kBody and the type of this param will be the scheme as class.
if (requestBody.content?.schema?.ref.isNotEmpty == true) {
result.add(
Parameter(
(p) => p
..name = kBody
..named = true
..required = true
..type = Reference(getValidatedClassName(requestBody.content!.schema!.ref.getRef()))
..named = true
..annotations.add(refer(kPart.pascalCase).call([])),
),
);

// early return
return result.distinctParameters();
}

if (schema?.properties.isEmpty == true) {
result.add(
Parameter(
Expand All @@ -814,7 +796,10 @@ class SwaggerRequestsGenerator extends SwaggerGeneratorBase {
// otherwise no request scheme is defined, we provide every param as a separate param.
schema?.properties.forEach((key, value) {
isBinary(SwaggerSchema? value) =>
(value?.type == 'string' && value?.format == 'binary') || value?.type == 'file';
(value?.type == 'string' &&
(value?.format == 'binary' ||
value?.contentMediaType.isNotEmpty == true)) ||
value?.type == 'file';
if ((isBinary(value) || value.type == 'array' && isBinary(value.items))) {
final isRequired = value.type == 'array' || schema!.required.contains(key);
String typeRef = isRequired
Expand All @@ -828,11 +813,13 @@ class SwaggerRequestsGenerator extends SwaggerGeneratorBase {
result.add(
Parameter(
(p) => p
..name = key
..name = SwaggerModelsGenerator.getValidatedParameterName(key)
..named = true
..required = isRequired
..type = Reference(typeRef)
..annotations.add(refer(kPartFile.pascalCase).call([])),
..annotations.add(
refer(kPartFile.pascalCase).call([literalString(key)]),
),
),
);
} else {
Expand Down
4 changes: 4 additions & 0 deletions lib/src/swagger_models/responses/swagger_schema.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ class SwaggerSchema {
this.ref = '',
this.defaultValue,
this.format = '',
this.contentMediaType = '',
this.schema,
this.oneOf = const [],
this.anyOf = const [],
Expand Down Expand Up @@ -65,6 +66,9 @@ class SwaggerSchema {
@JsonKey(name: 'format')
String format;

@JsonKey(name: 'contentMediaType')
String contentMediaType;

@JsonKey(name: 'default')
Object? defaultValue;

Expand Down
2 changes: 2 additions & 0 deletions lib/src/swagger_models/responses/swagger_schema.g.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

66 changes: 66 additions & 0 deletions test/generator_tests/requests_generator_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -68,4 +68,70 @@ void main() {
contains('Future<chopper.Response<CarModel>> carsMultipartPost'));
});
});

group('Multipart file upload', () {
final root = SwaggerRoot.parse(multipartRefService);

final result = SwaggerRequestsGenerator(GeneratorOptions(
inputFolder: '',
outputFolder: '',
ignoreHeaders: true,
)).generate(
swaggerRoot: root,
className: 'UploadService',
fileName: 'upload_service',
allEnums: [],
);

test('Should deparse a \$ref body into individual file parts', () {
expect(result, contains('@Multipart()'));
expect(result, contains("@PartFile('image') required List<int> image"));
expect(result, isNot(contains('required BodyUpload')));
});

test('Should treat OpenAPI 3.1 contentMediaType as binary', () {
expect(result, contains("@PartFile('doc') required List<int> doc"));
});

test('Should keep non-binary properties as plain @Part fields', () {
expect(result, contains("@Part('caption')"));
expect(result, isNot(contains("@PartFile('caption')")));
});
});
}

const multipartRefService = '''
{
"openapi": "3.1.0",
"info": {"title": "Upload", "version": "1.0.0"},
"paths": {
"/upload": {
"post": {
"operationId": "upload",
"requestBody": {
"required": true,
"content": {
"multipart/form-data": {
"schema": {"\$ref": "#/components/schemas/Body_upload"}
}
}
},
"responses": {"200": {"description": "ok"}}
}
}
},
"components": {
"schemas": {
"Body_upload": {
"type": "object",
"required": ["image", "doc"],
"properties": {
"image": {"type": "string", "format": "binary"},
"doc": {"type": "string", "contentMediaType": "application/octet-stream"},
"caption": {"type": "string"}
}
}
}
}
}
''';
Loading