Skip to content

Commit

Permalink
Update inline model resolver to flatten responses (OpenAPITools#19992)
Browse files Browse the repository at this point in the history
* update inline model resolver flatten responses

* minor update

* minor update

* minor update

* minor update
  • Loading branch information
wing328 authored Oct 30, 2024
1 parent 25b6fd3 commit cbc64e8
Show file tree
Hide file tree
Showing 7 changed files with 109 additions and 20 deletions.
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

0 comments on commit cbc64e8

Please sign in to comment.