Skip to content
Open
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
54 changes: 53 additions & 1 deletion docs/customization.md
Original file line number Diff line number Diff line change
Expand Up @@ -655,7 +655,7 @@ java -jar modules/openapi-generator-cli/target/openapi-generator-cli.jar generat

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
### Available FILTER 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`.
Expand All @@ -669,6 +669,9 @@ The `FILTER` parameter allows selective inclusion of API operations based on spe
- **`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.

- **`x-`**
When set to `x-role:admin|superuser`, operations or parameters having vendorExtension `x-role` with a value **not** in [`admin`,`superuser`] will be marked as internal (`x-internal: true`), and will not be generated.

### Example Usage

```sh
Expand Down Expand Up @@ -723,3 +726,52 @@ Into this securityScheme:
scheme: bearer
type: http
```

- `REMOVE_FILTER`

The `REMOVE_FILTER` parameter allows the removal of elements in an openAPI document. A semicolon can separate multiple filters.

### Available REMOVE_FILTER filters

- **`internal`**
When specified as `internal` or set to `internal:true`, all operations, schemas, properties and parameters marked with `x-internal: true` are removed from the document. Optionally set individual options like in `internal:operations|schemas|properties|parameters`

- **`deprecated`**
When specified as `deprecated` or set to `deprecated:true`, all operations, schemas, properties and parameters marked with `deprecated: true` are removed.

- **`removeTags`**
When specified as `removeTags` or set to `removeTags:true`, all tags are removed from the operations.
When set to `removeTags:store|user` all tags named is `store` or `user` are removed.
When set to `removeTags:keepOnlyFirstTag` perform the KEEP_ONLY_FIRST_TAG_IN_OPERATION normalization

- **`removeVendorExtensions`**
When specified as `removeVendorExtensions` or set to `removeVendorExtensions:true`, remove all vendorExtensions (including x-internal).
When set to `removeVendorExtensions:x-role|x-groups`, remove all `x-role` and `x-groups` vendorExtensions. When set to `removeVendorExtensions:x-internal`, perform the REMOVE_X_INTERNAL normalization.

- **`x-`**
When specified as `x-role`, remove operations, schemas, properties and parameters having a vendor extension `x-role`.
When set to `x-role:admin|superuser`, remove operations, schemas, properties and parameters marked with vendorExtension `x-role: admin` or `x-role: superuser`.

- **`tags`**
When set as `tags:user|store`, remove operations marked with tags: user or store.

- **`headers`**
When set as `headers`, remove all headers.
When set as `headers:x-api-key`, remove header parameters named `x-api-key`.

- **`cookies`**
When set as `cookies`, remove all cookies.
When set as `cookies:x-api-key`, remove cookie parameters named `x-api-key`.

- **`queryParams`**
When set as `queryParams:offset|limit`, remove request parameters named `offset` or `limit`.`.

- **`unused`**
When specified as `unused` or set to `unused:true`, remove all unused schemas, tags, requestBodies, responses and parameters.
Optionally set individual options like in `unused:schemas|tags|requestBodies|responses|parameters`

Example:
```
java -jar modules/openapi-generator-cli/target/openapi-generator-cli.jar generate -g openapi -i modules/openapi-generator/src/test/resources/3_1/java/petstore.yaml -o /tmp/openapi/ --openapi-normalizer FILTER=tag:pet --openapi-normalizer REMOVE_FILTER=internal;unused
```
generates an openapi.json without the store and user operations.

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,25 @@

package org.openapitools.codegen;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
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;
import io.swagger.v3.oas.models.responses.ApiResponse;
import io.swagger.v3.oas.models.security.SecurityScheme;
import lombok.Data;
import org.openapitools.codegen.serializer.SerializerUtils;
import org.openapitools.codegen.utils.ModelUtils;
import org.opentest4j.AssertionFailedError;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;

import java.lang.reflect.Array;
import java.io.*;
import java.net.URL;
import java.util.*;

import static org.testng.Assert.*;
Expand Down Expand Up @@ -694,7 +702,7 @@ public void testFilterParsing() {
// extra spaces are trimmed
filter = parseFilter("method:\n\t\t\t\tget");
assertTrue(filter.hasFilter());
assertEquals(filter.methodFilters, Set.of("get"));
assertEquals(filter.methodFilters, Set.of(PathItem.HttpMethod.GET));
assertTrue(filter.operationIdFilters.isEmpty());
assertTrue(filter.tagFilters.isEmpty());
assertTrue(filter.pathStartingWithFilters.isEmpty());
Expand Down Expand Up @@ -1288,4 +1296,71 @@ public Schema normalizeSchema(Schema schema, Set<Schema> visitedSchemas) {
}
}

/**
* get a list of all files matching openapi_normalizer/*_config.yaml.
*/
@DataProvider(name="testConfigs")
public Object[][] getTestConfigs() {
URL path = getClass().getClassLoader().getResource("openapi_normalizer");
File[] files = new File(path.getFile())
.listFiles(file -> file.getName().endsWith("_config.yaml"));

if (files == null || files.length == 0) {
throw new AssertionError("No test configs found in openapi_normalizer directory.");
}
return Arrays.stream(files)
.map(file -> new Object[]{"src/test/resources/openapi_normalizer/" +file.getName()})
.toArray(Object[][]::new);
}

@Test(dataProvider = "testConfigs")
public void executeAllTests(String specPath) {
OpenapiNormalizerTestConfig config = OpenapiNormalizerTestConfig.fromFile(specPath);
OpenAPI openAPI = TestUtils.parseSpec(config.inputSpec);
OpenAPINormalizer openAPINormalizer = OpenAPINormalizer.createNormalizer(openAPI, config.inputRules);
openAPINormalizer.normalize();
String expected = SerializerUtils.toYamlString(TestUtils.parseSpec(config.normalizedSpec));
String after = SerializerUtils.toYamlString(openAPI);
if (!expected.equals(after)) {
throw new AssertionFailedError("Unexpected normalized result for\n" + config, expected, after);
}
}

/**
* Custom remove filter used by custom_remove_filter_config.yaml
*/
public static class CustomRemoveFilter extends OpenAPINormalizer {
public CustomRemoveFilter(OpenAPI openAPI, Map<String, String> inputRules) {
super(openAPI, inputRules);
}

@Override
protected RemoveFilter createRemoveFilter(String filter) {
return new RemoveFilter(filter) {
protected boolean matchOperation(String path, PathItem.HttpMethod method, Operation operation) {
return operation.getExtensions() != null && "admin".equals(operation.getExtensions().get("x-role"));
}
};
}
}

/**
* Normalizer configuration in yaml files.
*/
@Data
static class OpenapiNormalizerTestConfig {
Map<String, String> inputRules;
String inputSpec;
String normalizedSpec;

static OpenapiNormalizerTestConfig fromFile(String specPath) {
ObjectMapper objectMapper = new ObjectMapper(new YAMLFactory());
try (InputStream inputStream = new FileInputStream(new File(specPath))) {
return objectMapper.readValue(inputStream, OpenapiNormalizerTestConfig.class);
} catch (IOException e) {
throw new RuntimeException("Unable to read from " + specPath, e);
}
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# test custom remove filter
inputSpec: src/test/resources/openapi_normalizer/petstore_with_roles.yaml
normalizedSpec: src/test/resources/openapi_normalizer/custom_remove_filter_normalized.yaml
inputRules:
NORMALIZER_CLASS: org.openapitools.codegen.OpenAPINormalizerTest$CustomRemoveFilter
REMOVE_FILTER: 'unused'
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
openapi: 3.0.0
info:
version: 1.0.0
servers:
- url: http://petstore.swagger.io/v2
paths:
/pet/{petId}:
get:
operationId: getPetById
parameters:
- description: ID of pet to return
explode: false
in: path
name: petId
required: true
schema:
format: int64
type: integer
style: simple
responses:
"200":
content:
application/json:
schema:
$ref: "#/components/schemas/Pet"
description: successful operation
put:
requestBody:
$ref: "#/components/requestBodies/Pet"
x-role: superuser
components:
requestBodies:
Pet:
content:
application/json:
schema:
$ref: "#/components/schemas/Pet"
description: Pet object that needs to be added to the store
required: true
schemas:
Category:
description: A category for a pet
properties:
id:
format: int64
type: integer
name:
type: string
title: Pet category
type: object
Tag:
description: A tag for a pet
properties:
id:
format: int64
type: integer
name:
type: string
title: Pet Tag
type: object
Pet:
description: A pet for sale in the pet store
properties:
id:
format: int64
type: integer
category:
$ref: "#/components/schemas/Category"
name:
type: string
tags:
items:
$ref: "#/components/schemas/Tag"
type: array
x-role: admin
required:
- name
- photoUrls
title: a Pet
type: object
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
openapi: 3.0.0
info:
version: 1.0.0
title: Test inline x-internal
components:
schemas:
ParentSchema:
description: Schema with inline x-internal property
type: object
properties:
normalProperty:
type: string
description: A normal property without x-internal
inlineXInternalProperty:
x-internal: true
description: Inline object property marked as x-internal
type: object
properties:
nestedField:
type: string
description: A field inside the inline x-internal object
nestedNumber:
type: integer
description: Another field inside the inline object
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# remove the elements having x-internal: true
inputSpec: src/test/resources/openapi_normalizer/inline_x_internal_test.yaml
normalizedSpec: src/test/resources/openapi_normalizer/inline_x_internal_test_normalized.yaml
inputRules:
REMOVE_FILTER: 'internal: properties'
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
openapi: 3.0.0
info:
version: 1.0.0
title: Test inline x-internal
components:
schemas:
ParentSchema:
description: Schema with inline x-internal property
type: object
properties:
normalProperty:
type: string
description: A normal property without x-internal

Loading
Loading