mirror of
https://github.com/OpenAPITools/openapi-generator.git
synced 2025-05-12 20:50:55 +00:00
Add tag and method filters during generation (#20801)
* Add Filter by tag and method under OpenAPINormalizer * Update message for invalid filters * Update customization documentation with new filters * Add comment for new code block
This commit is contained in:
parent
123119c076
commit
36b72052e6
@ -601,11 +601,29 @@ Example:
|
|||||||
java -jar modules/openapi-generator-cli/target/openapi-generator-cli.jar generate -g java -i modules/openapi-generator/src/test/resources/3_0/enableKeepOnlyFirstTagInOperation_test.yaml -o /tmp/java-okhttp/ --openapi-normalizer REMOVE_X_INTERNAL=true
|
java -jar modules/openapi-generator-cli/target/openapi-generator-cli.jar generate -g java -i modules/openapi-generator/src/test/resources/3_0/enableKeepOnlyFirstTagInOperation_test.yaml -o /tmp/java-okhttp/ --openapi-normalizer REMOVE_X_INTERNAL=true
|
||||||
```
|
```
|
||||||
|
|
||||||
- `FILTER`: When set to `operationId:addPet|getPetById` for example, it will add `x-internal:true` to operations with operationId not equal to addPet/getPetById (which will have x-internal set to false) so that these operations marked as internal won't be generated.
|
- `FILTER`
|
||||||
|
|
||||||
Example:
|
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.
|
||||||
```
|
|
||||||
java -jar modules/openapi-generator-cli/target/openapi-generator-cli.jar generate -g java -i modules/openapi-generator/src/test/resources/3_0/petstore.yaml -o /tmp/java-okhttp/ --openapi-normalizer FILTER="operationId:addPet|getPetById"
|
### Available Filters
|
||||||
|
|
||||||
|
- **`operationId`**
|
||||||
|
When set to `operationId:addPet|getPetById`, operations **not** matching `addPet` or `getPetById` will be marked as internal (`x-internal: true`), and excluded from generation. Matching operations will have `x-internal: false`.
|
||||||
|
|
||||||
|
- **`method`**
|
||||||
|
When set to `method:get|post`, operations **not** using `GET` or `POST` methods will be marked as internal (`x-internal: true`), preventing their generation.
|
||||||
|
|
||||||
|
- **`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.
|
||||||
|
|
||||||
|
### Example Usage
|
||||||
|
|
||||||
|
```sh
|
||||||
|
java -jar modules/openapi-generator-cli/target/openapi-generator-cli.jar generate \
|
||||||
|
-g java \
|
||||||
|
-i modules/openapi-generator/src/test/resources/3_0/petstore.yaml \
|
||||||
|
-o /tmp/java-okhttp/ \
|
||||||
|
--openapi-normalizer FILTER="operationId:addPet|getPetById"
|
||||||
```
|
```
|
||||||
|
|
||||||
- `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.
|
- `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.
|
||||||
|
@ -32,6 +32,7 @@ import org.slf4j.Logger;
|
|||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
import java.util.function.Function;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import static org.openapitools.codegen.utils.StringUtils.getUniqueString;
|
import static org.openapitools.codegen.utils.StringUtils.getUniqueString;
|
||||||
@ -119,6 +120,9 @@ public class OpenAPINormalizer {
|
|||||||
// when set (e.g. operationId:getPetById|addPet), filter out (or remove) everything else
|
// when set (e.g. operationId:getPetById|addPet), filter out (or remove) everything else
|
||||||
final String FILTER = "FILTER";
|
final String FILTER = "FILTER";
|
||||||
HashSet<String> operationIdFilters = new HashSet<>();
|
HashSet<String> operationIdFilters = new HashSet<>();
|
||||||
|
HashSet<String> methodFilters = new HashSet<>();
|
||||||
|
|
||||||
|
HashSet<String> tagFilters = new HashSet<>();
|
||||||
|
|
||||||
// when set (e.g. operationId:getPetById|addPet), filter out (or remove) everything else
|
// when set (e.g. operationId:getPetById|addPet), filter out (or remove) everything else
|
||||||
final String SET_CONTAINER_TO_NULLABLE = "SET_CONTAINER_TO_NULLABLE";
|
final String SET_CONTAINER_TO_NULLABLE = "SET_CONTAINER_TO_NULLABLE";
|
||||||
@ -238,15 +242,25 @@ public class OpenAPINormalizer {
|
|||||||
|
|
||||||
String[] filterStrs = inputRules.get(FILTER).split(":");
|
String[] filterStrs = inputRules.get(FILTER).split(":");
|
||||||
if (filterStrs.length != 2) { // only support operationId with : at the moment
|
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`: {}", inputRules.get(FILTER));
|
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 {
|
} else {
|
||||||
if ("operationId".equals(filterStrs[0])) {
|
if ("operationId".equals(filterStrs[0])) {
|
||||||
operationIdFilters = Arrays.stream(filterStrs[1].split("[|]"))
|
operationIdFilters = Arrays.stream(filterStrs[1].split("[|]"))
|
||||||
.filter(Objects::nonNull)
|
.filter(Objects::nonNull)
|
||||||
.map(String::trim)
|
.map(String::trim)
|
||||||
.collect(Collectors.toCollection(HashSet::new));
|
.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 {
|
} else {
|
||||||
LOGGER.error("FILTER rule must be in the form of `operationId:name1|name2|name3`: {}", inputRules.get(FILTER));
|
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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -338,6 +352,27 @@ public class OpenAPINormalizer {
|
|||||||
PathItem path = pathsEntry.getValue();
|
PathItem path = pathsEntry.getValue();
|
||||||
List<Operation> operations = new ArrayList<>(path.readOperations());
|
List<Operation> operations = new ArrayList<>(path.readOperations());
|
||||||
|
|
||||||
|
Map<String, Function<PathItem, Operation>> methodMap = Map.of(
|
||||||
|
"get", PathItem::getGet,
|
||||||
|
"put", PathItem::getPut,
|
||||||
|
"head", PathItem::getHead,
|
||||||
|
"post", PathItem::getPost,
|
||||||
|
"delete", PathItem::getDelete,
|
||||||
|
"patch", PathItem::getPatch,
|
||||||
|
"options", PathItem::getOptions,
|
||||||
|
"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));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// Include callback operation as well
|
// Include callback operation as well
|
||||||
for (Operation operation : path.readOperations()) {
|
for (Operation operation : path.readOperations()) {
|
||||||
Map<String, Callback> callbacks = operation.getCallbacks();
|
Map<String, Callback> callbacks = operation.getCallbacks();
|
||||||
@ -357,7 +392,14 @@ public class OpenAPINormalizer {
|
|||||||
if (operationIdFilters.contains(operation.getOperationId())) {
|
if (operationIdFilters.contains(operation.getOperationId())) {
|
||||||
operation.addExtension("x-internal", false);
|
operation.addExtension("x-internal", false);
|
||||||
} else {
|
} else {
|
||||||
LOGGER.info("operation `{}` marked as internal only (x-internal: true) by the FILTER", operation.getOperationId());
|
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);
|
operation.addExtension("x-internal", true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -485,7 +485,7 @@ public class OpenAPINormalizerTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testFilter() {
|
public void testOperationIdFilter() {
|
||||||
OpenAPI openAPI = TestUtils.parseSpec("src/test/resources/3_0/enableKeepOnlyFirstTagInOperation_test.yaml");
|
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}").getGet().getExtensions(), null);
|
||||||
@ -503,7 +503,7 @@ public class OpenAPINormalizerTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testFilterWithTrim() {
|
public void testOperationIdFilterWithTrim() {
|
||||||
OpenAPI openAPI = TestUtils.parseSpec("src/test/resources/3_0/enableKeepOnlyFirstTagInOperation_test.yaml");
|
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}").getGet().getExtensions(), null);
|
||||||
@ -520,6 +520,76 @@ public class OpenAPINormalizerTest {
|
|||||||
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"), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
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<String, String> options = new HashMap<>();
|
||||||
|
options.put("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"), true);
|
||||||
|
assertEquals(openAPI.getPaths().get("/person/display/{personId}").getPut().getExtensions().get("x-internal"), true);
|
||||||
|
}
|
||||||
|
@Test
|
||||||
|
public void testFilterWithMethodWithTrim() {
|
||||||
|
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<String, String> options = new HashMap<>();
|
||||||
|
options.put("FILTER", "method:\n\t\t\t\tget");
|
||||||
|
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"), true);
|
||||||
|
assertEquals(openAPI.getPaths().get("/person/display/{personId}").getPut().getExtensions().get("x-internal"), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@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<String, String> options = new HashMap<>();
|
||||||
|
options.put("FILTER", "tag:basic");
|
||||||
|
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"), true);
|
||||||
|
assertEquals(openAPI.getPaths().get("/person/display/{personId}").getPut().getExtensions().get("x-internal"), true);
|
||||||
|
}
|
||||||
|
@Test
|
||||||
|
public void testFilterWithTagWithTrim() {
|
||||||
|
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<String, String> options = new HashMap<>();
|
||||||
|
options.put("FILTER", "tag:basic");
|
||||||
|
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"), true);
|
||||||
|
assertEquals(openAPI.getPaths().get("/person/display/{personId}").getPut().getExtensions().get("x-internal"), true);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testComposedSchemaDoesNotThrow() {
|
public void testComposedSchemaDoesNotThrow() {
|
||||||
OpenAPI openAPI = TestUtils.parseSpec("src/test/resources/3_1/composed-schema.yaml");
|
OpenAPI openAPI = TestUtils.parseSpec("src/test/resources/3_1/composed-schema.yaml");
|
||||||
|
Loading…
x
Reference in New Issue
Block a user