Skip to content

Update inline model resolver to flatten responses #19992

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 5 commits into from
Oct 30, 2024
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 @@ -4774,7 +4774,7 @@ public CodegenOperation fromOperation(String path,
op.hasRequiredParams = op.requiredParams.size() > 0;

// check if the operation has only a single parameter
op.hasSingleParam = op.allParams.size() == 1;
op.hasSingleParam = op.allParams.size() == 1;

// set Restful Flag
op.isRestfulShow = op.isRestfulShow();
Expand Down Expand Up @@ -5724,7 +5724,7 @@ public void addOperationToGroup(String tag, String resourcePath, Operation opera
// check for operationId uniqueness
String uniqueName = co.operationId;
int counter = seenOperationIds.getOrDefault(uniqueName, 0);
while(seenOperationIds.containsKey(uniqueName)) {
while (seenOperationIds.containsKey(uniqueName)) {
uniqueName = co.operationId + "_" + counter;
counter++;
}
Expand Down Expand Up @@ -6120,7 +6120,7 @@ private String uniqueCaseInsensitiveString(String value, Map<String, String> see
return seenValues.get(value);
}

Optional<Entry<String,String>> foundEntry = seenValues.entrySet().stream().filter(v -> v.getValue().toLowerCase(Locale.ROOT).equals(value.toLowerCase(Locale.ROOT))).findAny();
Optional<Entry<String, String>> foundEntry = seenValues.entrySet().stream().filter(v -> v.getValue().toLowerCase(Locale.ROOT).equals(value.toLowerCase(Locale.ROOT))).findAny();
if (foundEntry.isPresent()) {
int counter = 0;
String uniqueValue = value + "_" + counter;
Expand Down Expand Up @@ -8181,7 +8181,7 @@ protected boolean executePostProcessor(String[] commandArr) {
int exitValue = p.exitValue();
if (exitValue != 0) {
try (InputStreamReader inputStreamReader = new InputStreamReader(p.getErrorStream(), StandardCharsets.UTF_8);
BufferedReader br = new BufferedReader(inputStreamReader)) {
BufferedReader br = new BufferedReader(inputStreamReader)) {
StringBuilder sb = new StringBuilder();
String line;
while ((line = br.readLine()) != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ void flatten(OpenAPI openAPI) {

flattenPaths();
flattenComponents();
flattenComponentResponses();
}

/**
Expand Down Expand Up @@ -352,7 +353,7 @@ private void gatherInlineModels(Schema schema, String modelPrefix) {
}

if (items == null) {
LOGGER.debug("prefixItems in array schema is not supported at the moment: {}", schema.toString());
LOGGER.debug("prefixItems in array schema is not supported at the moment: {}", schema.toString());
return;
}
String schemaName = resolveModelName(items.getTitle(), modelPrefix + this.inlineSchemaOptions.get("ARRAY_ITEM_SUFFIX"));
Expand Down Expand Up @@ -568,6 +569,20 @@ private void flattenResponses(String modelName, Operation operation) {
}
}

/**
* Flatten inline models in the responses section in the components.
*/
private void flattenComponentResponses() {
Map<String, ApiResponse> apiResponses = openAPI.getComponents().getResponses();
if (apiResponses == null) {
return;
}

for (Map.Entry<String, ApiResponse> entry : apiResponses.entrySet()) {
flattenContent(entry.getValue().getContent(), null);
}
}

/**
* Flattens properties of inline object schemas that belong to a composed schema into a
* single flat list of properties. This is useful to generate a single or multiple
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,7 @@ void normalize() {
normalizeInfo();
normalizePaths();
normalizeComponentsSchemas();
normalizeComponentsResponses();
}

/**
Expand Down Expand Up @@ -445,12 +446,19 @@ private void normalizeResponses(Operation operation) {
}

for (Map.Entry<String, ApiResponse> responsesEntry : responses.entrySet()) {
if (responsesEntry.getValue() == null) {
continue;
} else {
normalizeContent(ModelUtils.getReferencedApiResponse(openAPI, responsesEntry.getValue()).getContent());
normalizeHeaders(ModelUtils.getReferencedApiResponse(openAPI, responsesEntry.getValue()).getHeaders());
}
normalizeResponse(responsesEntry.getValue());
}
}

/**
* Normalizes schemas in ApiResponse
*
* @param apiResponse API response
*/
private void normalizeResponse(ApiResponse apiResponse) {
if (apiResponse != null) {
normalizeContent(ModelUtils.getReferencedApiResponse(openAPI, apiResponse).getContent());
normalizeHeaders(ModelUtils.getReferencedApiResponse(openAPI, apiResponse).getHeaders());
}
}

Expand Down Expand Up @@ -502,11 +510,25 @@ private void normalizeComponentsSchemas() {
}
}

/**
* Normalizes schemas in component's responses.
*/
private void normalizeComponentsResponses() {
Map<String, ApiResponse> apiResponses = openAPI.getComponents().getResponses();
if (apiResponses == null) {
return;
}

for (Map.Entry<String, ApiResponse> entry : apiResponses.entrySet()) {
normalizeResponse(entry.getValue());
}
}

/**
* Auto fix a self referencing schema using any type to replace the self-referencing sub-item.
*
* @param name Schema name
* @param schema Schema
* @param name Schema name
* @param schema Schema
*/
public void fixSelfReferenceSchema(String name, Schema schema) {
if (ModelUtils.isArraySchema(schema)) {
Expand Down Expand Up @@ -993,7 +1015,6 @@ private Schema processSimplifyAnyOfStringAndEnumString(Schema schema) {
}



/**
* If the schema is oneOf and the sub-schemas is null, set `nullable: true`
* instead.
Expand All @@ -1012,7 +1033,7 @@ private Schema processSimplifyOneOf(Schema schema) {
// simplify any type with 6 sub-schemas (string, integer, etc) in oneOf
if (oneOfSchemas.size() == 6) {
TreeSet<String> ts = new TreeSet<>();
for (Schema s: oneOfSchemas) {
for (Schema s : oneOfSchemas) {
s = ModelUtils.getReferencedSchema(openAPI, s);
String type = ModelUtils.getType(s);
if (type == null) {
Expand Down Expand Up @@ -1113,6 +1134,7 @@ private Schema setNullable(Schema schema) {
schema.setNullable(true);
return schema;
}

/**
* Set nullable to true in map if needed.
*
Expand Down Expand Up @@ -1148,7 +1170,7 @@ private Schema processSimplifyAnyOf(Schema schema) {
// simplify any type with 6 sub-schemas (string, integer, etc) in anyOf
if (anyOfSchemas.size() == 6) {
TreeSet<String> ts = new TreeSet<>();
for (Schema s: anyOfSchemas) {
for (Schema s : anyOfSchemas) {
s = ModelUtils.getReferencedSchema(openAPI, s);
String type = ModelUtils.getType(s);
if (type == null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -352,6 +352,14 @@ public void resolveInlineArraySchemaWithTitle() {
assertTrue(user.getProperties().get("city") instanceof StringSchema);
}

@Test
public void resolveComponentsResponses() {
OpenAPI openAPI = TestUtils.parseSpec("src/test/resources/3_0/inline_model_resolver.yaml");
new InlineModelResolver().flatten(openAPI);
ApiResponse apiResponse = openAPI.getComponents().getResponses().get("JustAnotherResponse");
assertEquals(apiResponse.getContent().get("application/json").getSchema().get$ref(), "#/components/schemas/inline_object");
}

@Test
public void resolveRequestBodyInvalidRef() {
OpenAPI openAPI = TestUtils.parseSpec("src/test/resources/3_0/invalid_ref_request_body.yaml");
Expand Down Expand Up @@ -1043,7 +1051,7 @@ public void testInlineSchemaNameMapping() {
public void testInlineSchemaOptions() {
OpenAPI openAPI = TestUtils.parseSpec("src/test/resources/3_0/inline_model_resolver.yaml");
InlineModelResolver resolver = new InlineModelResolver();
Map<String, String> inlineSchemaOptions= new HashMap<>();
Map<String, String> inlineSchemaOptions = new HashMap<>();
inlineSchemaOptions.put("ARRAY_ITEM_SUFFIX", "_something");
resolver.setInlineSchemaOptions(inlineSchemaOptions);
resolver.flatten(openAPI);
Expand Down Expand Up @@ -1135,7 +1143,7 @@ public void testNestedAnyOf() {
public void resolveOperationInlineEnum() {
OpenAPI openAPI = TestUtils.parseSpec("src/test/resources/3_0/inline_model_resolver.yaml");
Parameter parameter = openAPI.getPaths().get("/resolve_parameter_inline_enum").getGet().getParameters().get(0);
assertNull(((ArraySchema) parameter.getSchema()).getItems().get$ref() );
assertNull(((ArraySchema) parameter.getSchema()).getItems().get$ref());

InlineModelResolver resolver = new InlineModelResolver();
Map<String, String> inlineSchemaOptions = new HashMap<>();
Expand All @@ -1145,7 +1153,7 @@ public void resolveOperationInlineEnum() {

Parameter parameter2 = openAPI.getPaths().get("/resolve_parameter_inline_enum").getGet().getParameters().get(0);
assertEquals("#/components/schemas/resolveParameterInlineEnum_status_inline_enum_parameter_inner",
((ArraySchema) parameter2.getSchema()).getItems().get$ref() );
((ArraySchema) parameter2.getSchema()).getItems().get$ref());

}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,12 @@

package org.openapitools.codegen;

import io.swagger.annotations.Api;
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.PathItem;
import io.swagger.v3.oas.models.media.*;

import io.swagger.v3.oas.models.responses.ApiResponse;
import org.openapitools.codegen.utils.ModelUtils;
import org.testng.annotations.Test;

Expand Down Expand Up @@ -549,7 +551,7 @@ public void testSetPrimitiveTypesToNullable() {
}

@Test
public void testOpenAPINormalizerSimplifyOneOfAnyOf31SpecForIssue18184 () {
public void testOpenAPINormalizerSimplifyOneOfAnyOf31SpecForIssue18184() {
// to test the rule SIMPLIFY_ONEOF_ANYOF in 3.1 spec
OpenAPI openAPI = TestUtils.parseSpec("src/test/resources/3_1/issue_18184.yaml");
// test spec contains anyOf with a ref to enum and another scheme type is null
Expand Down Expand Up @@ -794,4 +796,22 @@ public void testOpenAPINormalizerProcessingAllOfSchema31Spec() {
assertEquals(((Schema) schema2.getProperties().get("property2")).getAllOf(), null);
assertEquals(((Schema) schema2.getProperties().get("property2")).getAllOf(), null);
}

@Test
public void testOpenAPINormalizerComponentsResponses31Spec() {
OpenAPI openAPI = TestUtils.parseSpec("src/test/resources/3_1/common-parameters.yaml");
ApiResponse apiResponse = openAPI.getComponents().getResponses().get("JustAnotherResponse");
assertEquals(((Schema) apiResponse.getContent().get("application/json").getSchema().getProperties().get("uuid")).getType(), null);
assertEquals(((Schema) apiResponse.getContent().get("application/json").getSchema().getProperties().get("label")).getType(), null);

Map<String, String> inputRules = Map.of(
"NORMALIZE_31SPEC", "true"
);
OpenAPINormalizer openAPINormalizer = new OpenAPINormalizer(openAPI, inputRules);
openAPINormalizer.normalize();

ApiResponse apiResponse2 = openAPI.getComponents().getResponses().get("JustAnotherResponse");
assertEquals(((Schema) apiResponse2.getContent().get("application/json").getSchema().getProperties().get("uuid")).getType(), "integer");
assertEquals(((Schema) apiResponse2.getContent().get("application/json").getSchema().getProperties().get("label")).getType(), "string");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -455,6 +455,18 @@ paths:
type: string
components:
requestBodies: {}
responses:
JustAnotherResponse:
description: just another response
content:
application/json:
schema:
type: object
properties:
uuid:
type: integer
label:
type: string
schemas:
Users:
type: array
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,18 @@ paths:
security:
- api_key: []
components:
responses:
JustAnotherResponse:
description: JustAnotherResponse
content:
application/json:
schema:
type: object
properties:
uuid:
type: integer
label:
type: string
requestBodies:
Pet:
content:
Expand Down
Loading