Skip to content
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

Apply style and explode values from encoding for form-encoded request body parameters #12162

Merged
merged 1 commit into from
May 19, 2022
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
Expand Up @@ -1925,16 +1925,49 @@ public void setParameterExampleValue(CodegenParameter codegenParameter, RequestB
}

/**
* Sets the content type of the parameter based on the encoding specified in the request body.
* Sets the content type, style, and explode of the parameter based on the encoding specified
* in the request body.
*
* @param codegenParameter Codegen parameter
* @param mediaType MediaType from the request body
*/
public void setParameterContentType(CodegenParameter codegenParameter, MediaType mediaType) {
public void setParameterEncodingValues(CodegenParameter codegenParameter, MediaType mediaType) {
if (mediaType != null && mediaType.getEncoding() != null) {
Encoding encoding = mediaType.getEncoding().get(codegenParameter.baseName);
if (encoding != null) {
codegenParameter.contentType = encoding.getContentType();
boolean styleGiven = true;
Encoding.StyleEnum style = encoding.getStyle();
if(style == null || style == Encoding.StyleEnum.FORM) {
// (Unfortunately, swagger-parser-v3 will always provide 'form'
// when style is not specified, so we can't detect that)
style = Encoding.StyleEnum.FORM;
styleGiven = false;
}
boolean explodeGiven = true;
Boolean explode = encoding.getExplode();
if(explode == null) {
explode = style == Encoding.StyleEnum.FORM; // Default to True when form, False otherwise
explodeGiven = false;
}

if(!styleGiven && !explodeGiven) {
// Ignore contentType if style or explode are specified.
codegenParameter.contentType = encoding.getContentType();
}

codegenParameter.style = style.toString();
codegenParameter.isDeepObject = Encoding.StyleEnum.DEEP_OBJECT == style;

if(codegenParameter.isContainer) {
codegenParameter.isExplode = explode;
String collectionFormat = getCollectionFormat(codegenParameter);
codegenParameter.collectionFormat = StringUtils.isEmpty(collectionFormat) ? "csv" : collectionFormat;
codegenParameter.isCollectionFormatMulti = "multi".equals(collectionFormat);
} else {
codegenParameter.isExplode = false;
codegenParameter.collectionFormat = null;
codegenParameter.isCollectionFormatMulti = false;
}
} else {
LOGGER.debug("encoding not specified for {}", codegenParameter.baseName);
}
Expand Down Expand Up @@ -4080,7 +4113,7 @@ public CodegenOperation fromOperation(String path,
formParams = fromRequestBodyToFormParameters(requestBody, imports);
op.isMultipart = contentType.startsWith("multipart");
for (CodegenParameter cp : formParams) {
setParameterContentType(cp, requestBody.getContent().get(contentType));
setParameterEncodingValues(cp, requestBody.getContent().get(contentType));
postProcessParameter(cp);
}
// add form parameters to the beginning of all parameter list
Expand Down Expand Up @@ -6391,11 +6424,12 @@ public CodegenParameter fromFormProperty(String name, Schema propertySchema, Set
LOGGER.warn("Could not compute datatypeWithEnum from {}, {}", arrayInnerProperty.baseType, arrayInnerProperty.enumName);
}
// end of hoisting
//TODO fix collectionFormat for form parameters
//collectionFormat = getCollectionFormat(s);

// collectionFormat for form parameter does not consider
// style and explode from encoding at this point
String collectionFormat = getCollectionFormat(codegenParameter);
// default to csv:
codegenParameter.collectionFormat = StringUtils.isEmpty(collectionFormat) ? "csv" : collectionFormat;
codegenParameter.isCollectionFormatMulti = "multi".equals(collectionFormat);

// recursively add import
while (arrayInnerProperty != null) {
Expand Down Expand Up @@ -6437,8 +6471,6 @@ public CodegenParameter fromFormProperty(String name, Schema propertySchema, Set
// set nullable
setParameterNullable(codegenParameter, codegenProperty);

//TODO collectionFormat for form parameter not yet supported
//codegenParameter.collectionFormat = getCollectionFormat(propertySchema);
return codegenParameter;
}

Expand Down Expand Up @@ -7360,14 +7392,30 @@ protected static boolean isJsonVendorMimeType(String mime) {
}

/**
* Returns null by default but can be overwritten to return a valid collectionFormat
* Builds OAPI 2.0 collectionFormat value based on style and explode values
* for the {@link CodegenParameter}.
*
* @param codegenParameter parameter
* @return string for a collectionFormat.
*/
protected String getCollectionFormat(CodegenParameter codegenParameter) {
return null;
if ("form".equals(codegenParameter.style)) {
// Ref: https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.1.md#style-values
if (codegenParameter.isExplode) {
return "multi";
} else {
return "csv";
}
} else if ("simple".equals(codegenParameter.style)) {
return "csv";
} else if ("pipeDelimited".equals(codegenParameter.style)) {
return "pipes";
} else if ("spaceDelimited".equals(codegenParameter.style)) {
return "ssv";
} else {
// Doesn't map to any of the collectionFormat strings
return null;
}
}

private CodegenComposedSchemas getComposedSchemas(Schema schema) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4049,6 +4049,44 @@ public void testRequestBodyContent() {
cp = mt.getSchema();
assertEquals(cp.baseName, "SchemaForRequestBodyTextPlain");
assertTrue(cp.isString);

path = "/requestBodyWithEncodingTypes";
co = codegen.fromOperation(path, "POST", openAPI.getPaths().get(path).getPost(), null);
List<CodegenParameter> formParams = co.formParams;

assertEquals(formParams.get(0).paramName, "intParam");
assertFalse(formParams.get(0).isContainer);
assertFalse(formParams.get(0).isExplode); // Should not be true for non-container

assertEquals(formParams.get(1).paramName, "explodeTrue");
assertTrue(formParams.get(1).isContainer);
assertEquals(formParams.get(1).style, Encoding.StyleEnum.FORM.toString());
assertTrue(formParams.get(1).isExplode);
assertNull(formParams.get(1).contentType);

assertEquals(formParams.get(2).paramName, "explodeFalse");
assertTrue(formParams.get(2).isContainer);
assertEquals(formParams.get(2).style, Encoding.StyleEnum.FORM.toString());
assertFalse(formParams.get(2).isExplode);
assertNull(formParams.get(2).contentType);

assertEquals(formParams.get(3).paramName, "noStyleNoExplode");
assertTrue(formParams.get(3).isContainer);
assertEquals(formParams.get(3).style, Encoding.StyleEnum.FORM.toString());
assertTrue(formParams.get(3).isExplode); // Defaults to true for style == FORM
assertEquals(formParams.get(3).contentType, "text/plain");

assertEquals(formParams.get(4).paramName, "styleSpecified");
assertTrue(formParams.get(4).isContainer);
assertEquals(formParams.get(4).style, Encoding.StyleEnum.SPACE_DELIMITED.toString());
assertFalse(formParams.get(4).isExplode);
assertNull(formParams.get(4).contentType);

assertEquals(formParams.get(5).paramName, "styleSpecifiedNoExplode");
assertTrue(formParams.get(5).isContainer);
assertEquals(formParams.get(5).style, Encoding.StyleEnum.SPACE_DELIMITED.toString());
assertFalse(formParams.get(5).isExplode); // Defaults to false for style other than FORM
assertNull(formParams.get(5).contentType);
}

@Test
Expand Down
51 changes: 51 additions & 0 deletions modules/openapi-generator/src/test/resources/3_0/content-data.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,57 @@ paths:
responses:
200:
description: OK
/requestBodyWithEncodingTypes:
post:
requestBody:
content:
application/x-www-form-urlencoded:
schema:
type: object
properties:
int-param:
type: integer
explode-true:
type: array
items:
type: string
explode-false:
type: array
items:
type: string
no-style-no-explode:
type: array
items:
type: string
style-specified:
type: array
items:
type: string
style-specified-no-explode:
type: array
items:
type: string
encoding:
int-param:
explode: true # should be disregarded for non-container
explode-true:
contentType: text/plain # should be disregarded
explode: true
explode-false:
contentType: text/plain # should be disregarded
explode: false
no-style-no-explode:
contentType: text/plain
style-specified:
contentType: text/plain # should be disregarded
style: spaceDelimited
explode: false
style-specified-no-explode:
contentType: text/plain # should be disregarded
style: spaceDelimited
responses:
200:
description: OK
components:
headers:
X-Rate-Limit:
Expand Down