diff --git a/docs/customization.md b/docs/customization.md index acb45936fd21..5cc0e972d158 100644 --- a/docs/customization.md +++ b/docs/customization.md @@ -645,7 +645,7 @@ java -jar modules/openapi-generator-cli/target/openapi-generator-cli.jar generat - `FILTER` -The `FILTER` parameter allows selective inclusion of API operations based on specific criteria. It applies the `x-internal: true` property to operations that do **not** match the specified values, preventing them from being generated. +The `FILTER` parameter allows selective inclusion of API operations based on specific criteria. It applies the `x-internal: true` property to operations that do **not** match the specified values, preventing them from being generated. Multiple filters can be separated by a semicolon. ### Available Filters @@ -658,6 +658,9 @@ The `FILTER` parameter allows selective inclusion of API operations based on spe - **`tag`** When set to `tag:person|basic`, operations **not** tagged with `person` or `basic` will be marked as internal (`x-internal: true`), and will not be generated. +- **`path`** + When set to `path:/v1|/v2`, operations on paths **not** starting with `/v1` or with `/v2` will be marked as internal (`x-internal: true`), and will not be generated. + ### Example Usage ```sh @@ -665,7 +668,7 @@ java -jar modules/openapi-generator-cli/target/openapi-generator-cli.jar generat -g java \ -i modules/openapi-generator/src/test/resources/3_0/petstore.yaml \ -o /tmp/java-okhttp/ \ - --openapi-normalizer FILTER="operationId:addPet|getPetById" + --openapi-normalizer FILTER="operationId:addPet|getPetById ; tag:store" ``` - `SET_CONTAINER_TO_NULLABLE`: When set to `array|set|map` (or just `array`) for example, it will set `nullable` in array, set and map to true. diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/OpenAPINormalizer.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/OpenAPINormalizer.java index c443c8a302b1..432ffd1bb29c 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/OpenAPINormalizer.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/OpenAPINormalizer.java @@ -49,7 +49,7 @@ public class OpenAPINormalizer { private TreeSet anyTypeTreeSet = new TreeSet<>(); - protected final Logger LOGGER = LoggerFactory.getLogger(OpenAPINormalizer.class); + protected static final Logger LOGGER = LoggerFactory.getLogger(OpenAPINormalizer.class); Set ruleNames = new TreeSet<>(); Set rulesDefaultToTrue = new TreeSet<>(); @@ -133,10 +133,6 @@ public class OpenAPINormalizer { // when set (e.g. operationId:getPetById|addPet), filter out (or remove) everything else final String FILTER = "FILTER"; - HashSet operationIdFilters = new HashSet<>(); - HashSet methodFilters = new HashSet<>(); - - HashSet tagFilters = new HashSet<>(); // when set (e.g. operationId:getPetById|addPet), filter out (or remove) everything else final String SET_CONTAINER_TO_NULLABLE = "SET_CONTAINER_TO_NULLABLE"; @@ -275,30 +271,7 @@ public void processRules(Map inputRules) { if (inputRules.get(FILTER) != null) { rules.put(FILTER, true); - - String[] filterStrs = inputRules.get(FILTER).split(":"); - if (filterStrs.length != 2) { // only support operationId with : at the moment - LOGGER.error("FILTER rule must be in the form of `operationId:name1|name2|name3` or `method:get|post|put` or `tag:tag1|tag2|tag3`: {}", inputRules.get(FILTER)); - } else { - if ("operationId".equals(filterStrs[0])) { - operationIdFilters = Arrays.stream(filterStrs[1].split("[|]")) - .filter(Objects::nonNull) - .map(String::trim) - .collect(Collectors.toCollection(HashSet::new)); - } else if ("method".equals(filterStrs[0])) { - methodFilters = Arrays.stream(filterStrs[1].split("[|]")) - .filter(Objects::nonNull) - .map(String::trim) - .collect(Collectors.toCollection(HashSet::new)); - } else if ("tag".equals(filterStrs[0])) { - tagFilters = Arrays.stream(filterStrs[1].split("[|]")) - .filter(Objects::nonNull) - .map(String::trim) - .collect(Collectors.toCollection(HashSet::new)); - } else { - LOGGER.error("FILTER rule must be in the form of `operationId:name1|name2|name3` or `method:get|post|put` or `tag:tag1|tag2|tag3`: {}", inputRules.get(FILTER)); - } - } + // actual parsing is delayed to allow customization of the Filter processing } if (inputRules.get(SET_CONTAINER_TO_NULLABLE) != null) { @@ -344,6 +317,19 @@ public void processRules(Map inputRules) { } } + /** + * Create the filter to process the FILTER normalizer. + * Override this to create a custom filter normalizer. + * + * @param openApi Contract used in the filtering (could be used for customization). + * @param filters full FILTER value + * + * @return a Filter containing the parsed filters. + */ + protected Filter createFilter(OpenAPI openApi, String filters) { + return new Filter(filters); + } + /** * Normalizes the OpenAPI input, which may not perfectly conform to * the specification. @@ -405,15 +391,15 @@ protected void normalizePaths() { "trace", PathItem::getTrace ); - // Iterates over each HTTP method in methodMap, retrieves the corresponding Operation from the PathItem, - // and marks it as internal (`x-internal`) if the method is not in methodFilters. - methodMap.forEach((method, getter) -> { - Operation operation = getter.apply(path); - if (operation != null && !methodFilters.isEmpty()) { - LOGGER.info("operation `{}` marked internal only (x-internal: `{}`) by the method FILTER", operation.getOperationId(), !methodFilters.contains(method)); - operation.addExtension("x-internal", !methodFilters.contains(method)); + if (Boolean.TRUE.equals(getRule(FILTER))) { + String filters = inputRules.get(FILTER); + Filter filter = createFilter(this.openAPI, filters); + if (filter.parse()) { + // Iterates over each HTTP method in methodMap, retrieves the corresponding Operations from the PathItem, + // and marks it as internal (`x-internal=true`) if the method/operationId/tag/path is not in the filters. + filter.apply(pathsEntry.getKey(), path, methodMap); } - }); + } // Include callback operation as well for (Operation operation : path.readOperations()) { @@ -430,22 +416,6 @@ protected void normalizePaths() { normalizeParameters(path.getParameters()); for (Operation operation : operations) { - if (operationIdFilters.size() > 0) { - if (operationIdFilters.contains(operation.getOperationId())) { - operation.addExtension(X_INTERNAL, false); - } else { - LOGGER.info("operation `{}` marked as internal only (x-internal: true) by the operationId FILTER", operation.getOperationId()); - operation.addExtension(X_INTERNAL, true); - } - } else if (!tagFilters.isEmpty()) { - if (operation.getTags().stream().anyMatch(tagFilters::contains)) { - operation.addExtension(X_INTERNAL, false); - } else { - LOGGER.info("operation `{}` marked as internal only (x-internal: true) by the tag FILTER", operation.getOperationId()); - operation.addExtension(X_INTERNAL, true); - } - } - normalizeOperation(operation); normalizeRequestBody(operation); normalizeParameters(operation.getParameters()); @@ -1363,7 +1333,7 @@ protected Schema processSimplifyOneOfEnum(Schema schema) { * * @param schema Schema to modify * @param subSchemas List of sub-schemas to check - * @param schemaType Type of composed schema ("oneOf" or "anyOf") + * @param composedType Type of composed schema ("oneOf" or "anyOf") * @return Simplified schema */ protected Schema simplifyComposedSchemaWithEnums(Schema schema, List subSchemas, String composedType) { @@ -1832,4 +1802,164 @@ protected Schema processNormalize31Spec(Schema schema, Set visitedSchema } // ===================== end of rules ===================== + + protected static class Filter { + public static final String OPERATION_ID = "operationId"; + public static final String METHOD = "method"; + public static final String TAG = "tag"; + public static final String PATH = "path"; + private final String filters; + protected Set operationIdFilters = Collections.emptySet(); + protected Set methodFilters = Collections.emptySet(); + protected Set tagFilters = Collections.emptySet(); + protected Set pathStartingWithFilters = Collections.emptySet(); + private boolean hasFilter; + + protected Filter(String filters) { + this.filters = filters.trim(); + } + + /** + * Perform the parsing of the filter string. + * + * @return true if filters need to be processed + */ + public boolean parse() { + if (StringUtils.isEmpty(filters)) { + return false; + } + try { + doParse(); + return hasFilter(); + } catch (RuntimeException e) { + String message = String.format(Locale.ROOT, "FILTER rule [%s] must be in the form of `%s:name1|name2|name3` or `%s:get|post|put` or `%s:tag1|tag2|tag3` or `%s:/v1|/v2`. Error: %s", + filters, Filter.OPERATION_ID, Filter.METHOD, Filter.TAG, Filter.PATH, e.getMessage()); + // throw an exception. This is a breaking change compared to pre 7.16.0 + // Workaround: fix the syntax! + throw new IllegalArgumentException(message); + } + } + + private void doParse() { + for (String filter : filters.split(";")) { + filter = filter.trim(); + String[] filterStrs = filter.split(":"); + if (filterStrs.length != 2) { // only support filter with : at the moment + throw new IllegalArgumentException("filter with no value not supported :[" + filter + "]"); + } else { + String filterKey = filterStrs[0].trim(); + String filterValue = filterStrs[1]; + Set parsedFilters = splitByPipe(filterValue); + hasFilter = true; + if (OPERATION_ID.equals(filterKey)) { + operationIdFilters = parsedFilters; + } else if (METHOD.equals(filterKey)) { + methodFilters = parsedFilters; + } else if (TAG.equals(filterKey)) { + tagFilters = parsedFilters; + } else if (PATH.equals(filterKey)) { + pathStartingWithFilters = parsedFilters; + } else { + parse(filterKey, filterValue); + } + } + } + } + + /** + * Split the filterValue by pipe. + * + * @return the split values. + */ + protected Set splitByPipe(String filterValue) { + return Arrays.stream(filterValue.split("[|]")) + .filter(Objects::nonNull) + .map(String::trim) + .collect(Collectors.toCollection(HashSet::new)); + } + + /** + * Parse non default filters. + * + * Override this method to add custom parsing logic. + * + * By default throws IllegalArgumentException. + * + * @param filterName name of the filter + * @param filterValue value of the filter + */ + protected void parse(String filterName, String filterValue) { + parseFails(filterName, filterValue); + } + + protected void parseFails(String filterName, String filterValue) { + throw new IllegalArgumentException("filter not supported :[" + filterName + ":" + filterValue + "]"); + } + + /** + * Test if the OpenAPI contract match an extra filter. + * + * Override this method to add custom logic. + * + * @param operation Openapi Operation + * @param path Path of the operation + * + * @return true if the operation of path match the filter + */ + protected boolean hasCustomFilterMatch(String path, Operation operation) { + return false; + } + + public boolean hasFilter() { + return hasFilter; + } + + public void apply(String path, PathItem pathItem, Map> methodMap) { + methodMap.forEach((method, getter) -> { + Operation operation = getter.apply(pathItem); + if (operation != null) { + boolean found = false; + found |= logIfMatch(PATH, operation, hasPathStarting(path)); + found |= logIfMatch(TAG, operation, hasTag(operation)); + found |= logIfMatch(OPERATION_ID, operation, hasOperationId(operation)); + found |= logIfMatch(METHOD, operation, hasMethod(method)); + found |= hasCustomFilterMatch(path, operation); + + operation.addExtension(X_INTERNAL, !found); + } + }); + } + + protected boolean logIfMatch(String filterName, Operation operation, boolean filterMatched) { + if (filterMatched) { + logMatch(filterName, operation); + } + return filterMatched; + } + + protected void logMatch(String filterName, Operation operation) { + getLogger().info("operation `{}` marked as internal only (x-internal: true) by the {} FILTER", operation.getOperationId(), filterName); + } + + protected Logger getLogger() { + return OpenAPINormalizer.LOGGER; + } + + private boolean hasPathStarting(String path) { + return pathStartingWithFilters.stream().anyMatch(filter -> path.startsWith(filter)); + } + + private boolean hasTag( Operation operation) { + return operation.getTags() != null && operation.getTags().stream().anyMatch(tagFilters::contains); + } + + private boolean hasOperationId(Operation operation) { + return operationIdFilters.contains(operation.getOperationId()); + } + + private boolean hasMethod(String method) { + return methodFilters.contains(method); + } + + } } diff --git a/modules/openapi-generator/src/test/java/org/openapitools/codegen/OpenAPINormalizerTest.java b/modules/openapi-generator/src/test/java/org/openapitools/codegen/OpenAPINormalizerTest.java index 833f991c9f60..a2567b78606c 100644 --- a/modules/openapi-generator/src/test/java/org/openapitools/codegen/OpenAPINormalizerTest.java +++ b/modules/openapi-generator/src/test/java/org/openapitools/codegen/OpenAPINormalizerTest.java @@ -17,6 +17,7 @@ package org.openapitools.codegen; import io.swagger.v3.oas.models.OpenAPI; +import io.swagger.v3.oas.models.Operation; import io.swagger.v3.oas.models.PathItem; import io.swagger.v3.oas.models.media.*; import io.swagger.v3.oas.models.parameters.Parameter; @@ -606,8 +607,7 @@ public void testRemoveXInternal() { assertEquals(openAPI.getPaths().get("/person/display/{personId}").getDelete().getExtensions().get(X_INTERNAL), true); assertEquals(s.getExtensions().get(X_INTERNAL), true); - Map options = new HashMap<>(); - options.put("REMOVE_X_INTERNAL", "true"); + Map options = Map.of("REMOVE_X_INTERNAL", "true"); OpenAPINormalizer openAPINormalizer = new OpenAPINormalizer(openAPI, options); openAPINormalizer.normalize(); @@ -623,46 +623,93 @@ public void testOperationIdFilter() { assertEquals(openAPI.getPaths().get("/person/display/{personId}").getGet().getExtensions(), null); assertEquals(openAPI.getPaths().get("/person/display/{personId}").getDelete().getExtensions().get(X_INTERNAL), true); - assertEquals(openAPI.getPaths().get("/person/display/{personId}").getPut().getExtensions(), null); - Map options = new HashMap<>(); - options.put("FILTER", "operationId:delete|list"); + Map options = Map.of("FILTER", "operationId:delete|list"); OpenAPINormalizer openAPINormalizer = new OpenAPINormalizer(openAPI, options); openAPINormalizer.normalize(); - assertEquals(openAPI.getPaths().get("/person/display/{personId}").getGet().getExtensions().get(X_INTERNAL), false); - assertEquals(openAPI.getPaths().get("/person/display/{personId}").getDelete().getExtensions().get(X_INTERNAL), false); - assertEquals(openAPI.getPaths().get("/person/display/{personId}").getPut().getExtensions().get(X_INTERNAL), true); + assertEquals(openAPI.getPaths().get("/person/display/{personId}").getGet().getExtensions().get("x-internal"), false); + assertEquals(openAPI.getPaths().get("/person/display/{personId}").getDelete().getExtensions().get("x-internal"), false); + assertEquals(openAPI.getPaths().get("/person/display/{personId}").getPut().getExtensions().get("x-internal"), true); } @Test - public void testOperationIdFilterWithTrim() { + public void testFilterWithMethod() { OpenAPI openAPI = TestUtils.parseSpec("src/test/resources/3_0/enableKeepOnlyFirstTagInOperation_test.yaml"); assertEquals(openAPI.getPaths().get("/person/display/{personId}").getGet().getExtensions(), null); assertEquals(openAPI.getPaths().get("/person/display/{personId}").getDelete().getExtensions().get(X_INTERNAL), true); - assertEquals(openAPI.getPaths().get("/person/display/{personId}").getPut().getExtensions(), null); - Map options = new HashMap<>(); - options.put("FILTER", "operationId:\n\t\t\t\tdelete|\n\t\tlist"); + Map options = Map.of("FILTER", "method:get"); OpenAPINormalizer openAPINormalizer = new OpenAPINormalizer(openAPI, options); openAPINormalizer.normalize(); assertEquals(openAPI.getPaths().get("/person/display/{personId}").getGet().getExtensions().get(X_INTERNAL), false); - assertEquals(openAPI.getPaths().get("/person/display/{personId}").getDelete().getExtensions().get(X_INTERNAL), false); + assertEquals(openAPI.getPaths().get("/person/display/{personId}").getDelete().getExtensions().get(X_INTERNAL), true); assertEquals(openAPI.getPaths().get("/person/display/{personId}").getPut().getExtensions().get(X_INTERNAL), true); } + static OpenAPINormalizer.Filter parseFilter(String filters) { + OpenAPINormalizer.Filter filter = new OpenAPINormalizer.Filter(filters); + filter.parse(); + return filter; + } + @Test - public void testFilterWithMethod() { + public void testFilterParsing() { + OpenAPINormalizer.Filter filter; + + // no filter + filter = parseFilter(" "); + assertFalse(filter.hasFilter()); + + // invalid filter + assertThrows(IllegalArgumentException.class, () -> + parseFilter("operationId:")); + + assertThrows(IllegalArgumentException.class, () -> + parseFilter("invalid:invalid:")); + + // extra spaces are trimmed + filter = parseFilter("method:\n\t\t\t\tget"); + assertTrue(filter.hasFilter()); + assertEquals(filter.methodFilters, Set.of("get")); + assertTrue(filter.operationIdFilters.isEmpty()); + assertTrue(filter.tagFilters.isEmpty()); + assertTrue(filter.pathStartingWithFilters.isEmpty()); + + // multiple values separated by pipe + filter = parseFilter("operationId:\n\t\t\t\tdelete|\n\t\tlist\t"); + assertTrue(filter.hasFilter()); + assertTrue(filter.methodFilters.isEmpty()); + assertEquals(filter.operationIdFilters, Set.of("delete", "list")); + assertTrue(filter.tagFilters.isEmpty()); + assertTrue(filter.pathStartingWithFilters.isEmpty()); + + // multiple filters + filter = parseFilter("operationId:delete|list;path:/v1"); + assertTrue(filter.hasFilter()); + assertTrue(filter.methodFilters.isEmpty()); + assertEquals(filter.operationIdFilters, Set.of("delete", "list")); + assertTrue(filter.tagFilters.isEmpty()); + assertEquals(filter.pathStartingWithFilters, Set.of("/v1")); + } + + @Test + public void testMultiFilterParsing() { + OpenAPINormalizer.Filter filter = parseFilter("operationId: delete| list ; tag : testA |testB "); + assertEquals(filter.operationIdFilters, Set.of("delete", "list")); + assertEquals(filter.tagFilters, Set.of("testA", "testB")); + } + + @Test + public void testFilterWithTag() { OpenAPI openAPI = TestUtils.parseSpec("src/test/resources/3_0/enableKeepOnlyFirstTagInOperation_test.yaml"); assertEquals(openAPI.getPaths().get("/person/display/{personId}").getGet().getExtensions(), null); assertEquals(openAPI.getPaths().get("/person/display/{personId}").getDelete().getExtensions().get(X_INTERNAL), true); - assertEquals(openAPI.getPaths().get("/person/display/{personId}").getPut().getExtensions(), null); - Map options = new HashMap<>(); - options.put("FILTER", "method:get"); + Map options = Map.of("FILTER", "tag:basic"); OpenAPINormalizer openAPINormalizer = new OpenAPINormalizer(openAPI, options); openAPINormalizer.normalize(); @@ -670,59 +717,74 @@ public void testFilterWithMethod() { assertEquals(openAPI.getPaths().get("/person/display/{personId}").getDelete().getExtensions().get(X_INTERNAL), true); assertEquals(openAPI.getPaths().get("/person/display/{personId}").getPut().getExtensions().get(X_INTERNAL), true); } + @Test - public void testFilterWithMethodWithTrim() { + public void testCustomRoleFilter() { OpenAPI openAPI = TestUtils.parseSpec("src/test/resources/3_0/enableKeepOnlyFirstTagInOperation_test.yaml"); - assertEquals(openAPI.getPaths().get("/person/display/{personId}").getGet().getExtensions(), null); - assertEquals(openAPI.getPaths().get("/person/display/{personId}").getDelete().getExtensions().get(X_INTERNAL), true); - assertEquals(openAPI.getPaths().get("/person/display/{personId}").getPut().getExtensions(), null); - - Map options = new HashMap<>(); - options.put("FILTER", "method:\n\t\t\t\tget"); - OpenAPINormalizer openAPINormalizer = new OpenAPINormalizer(openAPI, options); + Map options = Map.of("FILTER", "role:admin"); + OpenAPINormalizer openAPINormalizer = new OpenAPINormalizer(openAPI, options) { + @Override + protected Filter createFilter(OpenAPI openApi, String filters) { + return new CustomRoleFilter(filters); + } + }; openAPINormalizer.normalize(); - assertEquals(openAPI.getPaths().get("/person/display/{personId}").getGet().getExtensions().get(X_INTERNAL), false); + assertEquals(openAPI.getPaths().get("/person/display/{personId}").getGet().getExtensions().get(X_INTERNAL), true); assertEquals(openAPI.getPaths().get("/person/display/{personId}").getDelete().getExtensions().get(X_INTERNAL), true); - assertEquals(openAPI.getPaths().get("/person/display/{personId}").getPut().getExtensions().get(X_INTERNAL), true); + assertEquals(openAPI.getPaths().get("/person/display/{personId}").getPut().getExtensions().get(X_INTERNAL), false); } - @Test - public void testFilterWithTag() { - OpenAPI openAPI = TestUtils.parseSpec("src/test/resources/3_0/enableKeepOnlyFirstTagInOperation_test.yaml"); + private class CustomRoleFilter extends OpenAPINormalizer.Filter { + private Set filteredRoles; - assertEquals(openAPI.getPaths().get("/person/display/{personId}").getGet().getExtensions(), null); - assertEquals(openAPI.getPaths().get("/person/display/{personId}").getDelete().getExtensions().get(X_INTERNAL), true); - assertEquals(openAPI.getPaths().get("/person/display/{personId}").getPut().getExtensions(), null); + public CustomRoleFilter(String filters) { + super(filters); + } - Map options = new HashMap<>(); - options.put("FILTER", "tag:basic"); - OpenAPINormalizer openAPINormalizer = new OpenAPINormalizer(openAPI, options); - openAPINormalizer.normalize(); + @Override + protected void parse(String filterName, String filterValue) { + if ("role".equals(filterName)) { + this.filteredRoles = splitByPipe(filterValue); + } else { + parseFails(filterName, filterValue); + } + } - assertEquals(openAPI.getPaths().get("/person/display/{personId}").getGet().getExtensions().get(X_INTERNAL), false); - assertEquals(openAPI.getPaths().get("/person/display/{personId}").getDelete().getExtensions().get(X_INTERNAL), true); - assertEquals(openAPI.getPaths().get("/person/display/{personId}").getPut().getExtensions().get(X_INTERNAL), true); + @Override + protected boolean hasCustomFilterMatch(String path, Operation operation) { + return operation.getExtensions() != null && filteredRoles.contains(operation.getExtensions().get("x-role")); + } } + @Test - public void testFilterWithTagWithTrim() { + public void testFilterInvalidSyntaxDoesThrow() { OpenAPI openAPI = TestUtils.parseSpec("src/test/resources/3_0/enableKeepOnlyFirstTagInOperation_test.yaml"); - assertEquals(openAPI.getPaths().get("/person/display/{personId}").getGet().getExtensions(), null); - assertEquals(openAPI.getPaths().get("/person/display/{personId}").getDelete().getExtensions().get(X_INTERNAL), true); - assertEquals(openAPI.getPaths().get("/person/display/{personId}").getPut().getExtensions(), null); + Map options = Map.of("FILTER", "tag ; invalid"); + try { + new OpenAPINormalizer(openAPI, options).normalize(); + fail("Expected IllegalArgumentException"); + } catch (IllegalArgumentException e) { + assertEquals(e.getMessage(), "FILTER rule [tag ; invalid] must be in the form of `operationId:name1|name2|name3` or `method:get|post|put` or `tag:tag1|tag2|tag3` or `path:/v1|/v2`. Error: filter with no value not supported :[tag]"); + } + } - Map options = new HashMap<>(); - options.put("FILTER", "tag:basic"); - OpenAPINormalizer openAPINormalizer = new OpenAPINormalizer(openAPI, options); - openAPINormalizer.normalize(); + @Test + public void testFilterInvalidFilterDoesThrow() { + OpenAPI openAPI = TestUtils.parseSpec("src/test/resources/3_0/enableKeepOnlyFirstTagInOperation_test.yaml"); - assertEquals(openAPI.getPaths().get("/person/display/{personId}").getGet().getExtensions().get(X_INTERNAL), false); - assertEquals(openAPI.getPaths().get("/person/display/{personId}").getDelete().getExtensions().get(X_INTERNAL), true); - assertEquals(openAPI.getPaths().get("/person/display/{personId}").getPut().getExtensions().get(X_INTERNAL), true); + Map options = Map.of("FILTER", "method:get ; unknown:test"); + try { + new OpenAPINormalizer(openAPI, options).normalize(); + fail("Expected IllegalArgumentException"); + } catch (IllegalArgumentException e) { + assertEquals(e.getMessage(), "FILTER rule [method:get ; unknown:test] must be in the form of `operationId:name1|name2|name3` or `method:get|post|put` or `tag:tag1|tag2|tag3` or `path:/v1|/v2`. Error: filter not supported :[unknown:test]"); + } } + @Test public void testComposedSchemaDoesNotThrow() { OpenAPI openAPI = TestUtils.parseSpec("src/test/resources/3_1/composed-schema.yaml"); @@ -1204,4 +1266,5 @@ public Schema normalizeSchema(Schema schema, Set visitedSchemas) { return super.normalizeSchema(schema, visitedSchemas); } } + } diff --git a/modules/openapi-generator/src/test/resources/3_0/enableKeepOnlyFirstTagInOperation_test.yaml b/modules/openapi-generator/src/test/resources/3_0/enableKeepOnlyFirstTagInOperation_test.yaml index 04abd51fc985..823504bf6f5e 100644 --- a/modules/openapi-generator/src/test/resources/3_0/enableKeepOnlyFirstTagInOperation_test.yaml +++ b/modules/openapi-generator/src/test/resources/3_0/enableKeepOnlyFirstTagInOperation_test.yaml @@ -7,6 +7,18 @@ info: servers: - url: http://api.example.xyz/v1 paths: + /v1/person: + get: + operationId: list + responses: + '200': + description: OK + /v2/person: + get: + operationId: list + responses: + '200': + description: OK /person/display/{personId}: get: tags: @@ -47,6 +59,7 @@ paths: schema: $ref: "#/components/schemas/Person" put: + x-role: admin tags: - person parameters: @@ -83,4 +96,4 @@ components: type: object properties: test: - type: string \ No newline at end of file + type: string