Skip to content

[dart] Improve content-type handling #9517

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
May 24, 2021
Merged
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
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package org.openapitools.codegen.languages;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import io.swagger.v3.oas.models.Operation;
import io.swagger.v3.oas.models.media.ArraySchema;
Expand Down Expand Up @@ -29,6 +28,9 @@ public abstract class AbstractDartCodegen extends DefaultCodegen {

private static final Logger LOGGER = LoggerFactory.getLogger(AbstractDartCodegen.class);

protected static final List<String> DEFAULT_SUPPORTED_CONTENT_TYPES = Arrays.asList(
"application/json", "application/x-www-form-urlencoded", "multipart/form-data");

public static final String PUB_LIBRARY = "pubLibrary";
public static final String PUB_NAME = "pubName";
public static final String PUB_VERSION = "pubVersion";
Expand Down Expand Up @@ -556,6 +558,68 @@ public CodegenOperation fromOperation(String path, String httpMethod, Operation
return op;
}

@Override
public Map<String, Object> postProcessOperationsWithModels(Map<String, Object> objs, List<Object> allModels) {
super.postProcessOperationsWithModels(objs, allModels);
Map<String, Object> operations = (Map<String, Object>) objs.get("operations");
if (operations != null) {
List<CodegenOperation> ops = (List<CodegenOperation>) operations.get("operation");
for (CodegenOperation op : ops) {
if (op.hasConsumes) {
if (!op.formParams.isEmpty() || op.isMultipart) {
// DefaultCodegen only sets this if the first consumes mediaType
// is application/x-www-form-urlencoded or multipart.
// Can just use the original
op.prioritizedContentTypes = op.consumes;
} else {
// Prioritize content types by moving application/json to the front
// similar to JavaCodegen
op.prioritizedContentTypes = prioritizeContentTypes(op.consumes);
String mediaType = op.prioritizedContentTypes.get(0).get("mediaType");
if (!DEFAULT_SUPPORTED_CONTENT_TYPES.contains(mediaType)) {
LOGGER.warn("The media-type '{}' for operation '{}' is not support in the Dart generators by default.", mediaType, op.path);
}
}
}
}
}
return objs;
}

private List<Map<String, String>> prioritizeContentTypes(List<Map<String, String>> consumes) {
if (consumes.size() <= 1) {
// no need to change any order
return consumes;
}

List<Map<String, String>> prioritizedContentTypes = new ArrayList<>(consumes.size());

List<Map<String, String>> jsonVendorMimeTypes = new ArrayList<>(consumes.size());
List<Map<String, String>> jsonMimeTypes = new ArrayList<>(consumes.size());

for (Map<String, String> consume : consumes) {
String mediaType = consume.get("mediaType");
if (isJsonVendorMimeType(mediaType)) {
jsonVendorMimeTypes.add(consume);
} else if (isJsonMimeType(mediaType)) {
jsonMimeTypes.add(consume);
} else {
prioritizedContentTypes.add(consume);
}
}

prioritizedContentTypes.addAll(0, jsonMimeTypes);
prioritizedContentTypes.addAll(0, jsonVendorMimeTypes);
return prioritizedContentTypes;
}

private static boolean isMultipartType(String mediaType) {
if (mediaType != null) {
return "multipart/form-data".equals(mediaType);
}
return false;
}

@Override
protected void updateEnumVarsWithExtensions(List<Map<String, Object>> enumVars, Map<String, Object> vendorExtensions, String dataType) {
if (vendorExtensions != null && useEnumExtension && vendorExtensions.containsKey("x-enum-values")) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -264,32 +264,16 @@ private void appendCollection(StringBuilder sb, CodegenProperty property) {

@Override
public Map<String, Object> postProcessOperationsWithModels(Map<String, Object> objs, List<Object> allModels) {
objs = super.postProcessOperationsWithModels(objs, allModels);
super.postProcessOperationsWithModels(objs, allModels);
Map<String, Object> operations = (Map<String, Object>) objs.get("operations");
List<CodegenOperation> operationList = (List<CodegenOperation>) operations.get("operation");

Set<Map<String, Object>> serializers = new HashSet<>();
Set<String> resultImports = new HashSet<>();

for (CodegenOperation op : operationList) {
op.httpMethod = op.httpMethod.toLowerCase(Locale.ROOT);
boolean isJson = true; //default to JSON
boolean isForm = false;
boolean isMultipart = false;
if (op.consumes != null) {
for (Map<String, String> consume : op.consumes) {
if (consume.containsKey("mediaType")) {
String type = consume.get("mediaType");
isJson = type.equalsIgnoreCase("application/json");
isForm = type.equalsIgnoreCase("application/x-www-form-urlencoded");
isMultipart = type.equalsIgnoreCase("multipart/form-data");
break;
}
}
}

for (CodegenParameter param : op.bodyParams) {
if (param.baseType != null && param.baseType.equalsIgnoreCase("Uint8List") && isMultipart) {
if (param.baseType != null && param.baseType.equalsIgnoreCase("Uint8List") && op.isMultipart) {
param.baseType = "MultipartFile";
param.dataType = "MultipartFile";
}
Expand All @@ -303,10 +287,6 @@ public Map<String, Object> postProcessOperationsWithModels(Map<String, Object> o
}
}

op.vendorExtensions.put("x-is-json", isJson);
op.vendorExtensions.put("x-is-form", isForm);
op.vendorExtensions.put("x-is-multipart", isMultipart);

resultImports.addAll(rewriteImports(op.imports));
if (op.getHasFormParams()) {
resultImports.add("package:" + pubName + "/api_util.dart");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -305,32 +305,16 @@ private void appendBuiltValueCollection(StringBuilder sb, CodegenProperty proper

@Override
public Map<String, Object> postProcessOperationsWithModels(Map<String, Object> objs, List<Object> allModels) {
objs = super.postProcessOperationsWithModels(objs, allModels);
super.postProcessOperationsWithModels(objs, allModels);
Map<String, Object> operations = (Map<String, Object>) objs.get("operations");
List<CodegenOperation> operationList = (List<CodegenOperation>) operations.get("operation");

Set<Map<String, Object>> serializers = new HashSet<>();
Set<String> resultImports = new HashSet<>();

for (CodegenOperation op : operationList) {
op.httpMethod = op.httpMethod.toLowerCase(Locale.ROOT);
boolean isJson = true; //default to JSON
boolean isForm = false;
boolean isMultipart = false;
if (op.consumes != null) {
for (Map<String, String> consume : op.consumes) {
if (consume.containsKey("mediaType")) {
String type = consume.get("mediaType");
isJson = type.equalsIgnoreCase("application/json");
isForm = type.equalsIgnoreCase("application/x-www-form-urlencoded");
isMultipart = type.equalsIgnoreCase("multipart/form-data");
break;
}
}
}

for (CodegenParameter param : op.bodyParams) {
if (param.baseType != null && param.baseType.equalsIgnoreCase("Uint8List") && isMultipart) {
if (param.baseType != null && param.baseType.equalsIgnoreCase("Uint8List") && op.isMultipart) {
param.baseType = "MultipartFile";
param.dataType = "MultipartFile";
}
Expand All @@ -344,10 +328,6 @@ public Map<String, Object> postProcessOperationsWithModels(Map<String, Object> o
}
}

op.vendorExtensions.put("x-is-json", isJson);
op.vendorExtensions.put("x-is-form", isForm);
op.vendorExtensions.put("x-is-multipart", isMultipart);

resultImports.addAll(rewriteImports(op.imports));
if (op.getHasFormParams()) {
resultImports.add("package:" + pubName + "/src/api_util.dart");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,10 +63,7 @@ class {{classname}} {
...?extra,
},
validateStatus: validateStatus,
contentType: [{{^hasConsumes}}
'application/json',{{/hasConsumes}}{{#hasConsumes}}{{#consumes}}
'{{{mediaType}}}',{{/consumes}}{{/hasConsumes}}
].first,
contentType: '{{^hasConsumes}}application/json{{/hasConsumes}}{{#hasConsumes}}{{#prioritizedContentTypes}}{{#-first}}{{{mediaType}}}{{/-first}}{{/prioritizedContentTypes}}{{/hasConsumes}}',
cancelToken: cancelToken,
onSendProgress: onSendProgress,
onReceiveProgress: onReceiveProgress,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,11 +60,8 @@ class {{classname}} {
},{{/authMethods}}
],{{/hasAuthMethods}}
...?extra,
},
contentType: [{{^hasConsumes}}
'application/json',{{/hasConsumes}}{{#hasConsumes}}{{#consumes}}
'{{{mediaType}}}',{{/consumes}}{{/hasConsumes}}
].first,
},{{#hasConsumes}}
contentType: '{{#prioritizedContentTypes}}{{#-first}}{{{mediaType}}}{{/-first}}{{/prioritizedContentTypes}}',{{/hasConsumes}}
validateStatus: validateStatus,
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ class {{{classname}}} {
{{/headerParams}}
{{/hasHeaderParams}}

final contentTypes = <String>[{{#consumes}}'{{{mediaType}}}'{{^-last}}, {{/-last}}{{/consumes}}];
final contentTypes = <String>[{{#prioritizedContentTypes}}'{{{mediaType}}}'{{^-last}}, {{/-last}}{{/prioritizedContentTypes}}];
final nullableContentType = contentTypes.isNotEmpty ? contentTypes[0] : null;
final authNames = <String>[{{#authMethods}}'{{{name}}}'{{^-last}}, {{/-last}}{{/authMethods}}];

Expand Down
Loading