Add rule to remove x-internal in openapi normalizer (#17734)

* add rule to remove x-internal in normalizer

* update

* update doc

* better code format

* update samples
This commit is contained in:
William Cheng
2024-01-30 21:11:25 +08:00
committed by GitHub
parent 301f25a306
commit 59f672d9aa
9 changed files with 118 additions and 223 deletions

View File

@@ -571,3 +571,9 @@ Example:
java -jar modules/openapi-generator-cli/target/openapi-generator-cli.jar generate -g java -i modules/openapi-generator/src/test/resources/3_0/allOf_extension_parent.yaml -o /tmp/java-okhttp/ --openapi-normalizer REFACTOR_ALLOF_WITH_PROPERTIES_ONLY=true
```
- `REMOVE_X_INTERNAL`: When set to true, remove `x-internal` extension from operations and models.
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
```

View File

@@ -4507,11 +4507,6 @@ public class DefaultCodegen implements CodegenConfig {
if (operation == null)
throw new RuntimeException("operation cannot be null in fromOperation");
if (operation.getExtensions() != null && Boolean.TRUE.equals(operation.getExtensions().get("x-internal"))) {
LOGGER.info("Operation ({} {} - {}) not generated since x-internal is set to true",
httpMethod, path, operation.getOperationId());
}
Map<String, Schema> schemas = ModelUtils.getSchemas(this.openAPI);
CodegenOperation op = CodegenModelFactory.newInstance(CodegenModelType.OPERATION);
Set<String> imports = new HashSet<>();
@@ -5083,25 +5078,31 @@ public class DefaultCodegen implements CodegenConfig {
String method = p.getKey();
Operation op = p.getValue();
boolean genId = op.getOperationId() == null;
if (genId) {
op.setOperationId(getOrGenerateOperationId(op, c.name + "_" + expression.replaceAll("\\{\\$.*}", ""), method));
}
if (op.getExtensions() != null && Boolean.TRUE.equals(op.getExtensions().get("x-internal"))) {
// skip operation if x-internal sets to true
LOGGER.info("Operation ({} {} - {}) not generated since x-internal is set to true",
method, expression, op.getOperationId());
} else {
boolean genId = op.getOperationId() == null;
if (genId) {
op.setOperationId(getOrGenerateOperationId(op, c.name + "_" + expression.replaceAll("\\{\\$.*}", ""), method));
}
if (op.getExtensions() == null) {
op.setExtensions(new HashMap<>());
}
// This extension will be removed later by `fromOperation()` as it is only needed here to
// distinguish between normal operations and callback requests
op.getExtensions().put("x-callback-request", true);
if (op.getExtensions() == null) {
op.setExtensions(new HashMap<>());
}
// This extension will be removed later by `fromOperation()` as it is only needed here to
// distinguish between normal operations and callback requests
op.getExtensions().put("x-callback-request", true);
CodegenOperation co = fromOperation(expression, method, op, servers);
if (genId) {
co.operationIdOriginal = null;
// legacy (see `fromOperation()`)
co.nickname = co.operationId;
CodegenOperation co = fromOperation(expression, method, op, servers);
if (genId) {
co.operationIdOriginal = null;
// legacy (see `fromOperation()`)
co.nickname = co.operationId;
}
u.requests.add(co);
}
u.requests.add(co);
});
c.urls.add(u);

View File

@@ -1492,31 +1492,36 @@ public class DefaultGenerator implements Generator {
final List<SecurityRequirement> globalSecurities = openAPI.getSecurity();
for (Tag tag : tags) {
try {
CodegenOperation codegenOperation = config.fromOperation(resourcePath, httpMethod, operation, path.getServers());
codegenOperation.tags = new ArrayList<>(tags);
config.addOperationToGroup(config.sanitizeTag(tag.getName()), resourcePath, operation, codegenOperation, operations);
List<SecurityRequirement> securities = operation.getSecurity();
if (securities != null && securities.isEmpty()) {
continue;
}
Map<String, SecurityScheme> authMethods = getAuthMethods(securities, securitySchemes);
if (authMethods != null && !authMethods.isEmpty()) {
List<CodegenSecurity> fullAuthMethods = config.fromSecurity(authMethods);
codegenOperation.authMethods = filterAuthMethods(fullAuthMethods, securities);
codegenOperation.hasAuthMethods = true;
if (operation.getExtensions() != null && Boolean.TRUE.equals(operation.getExtensions().get("x-internal"))) {
// skip operation if x-internal sets to true
LOGGER.info("Operation ({} {} - {}) not generated since x-internal is set to true",
httpMethod, resourcePath, operation.getOperationId());
} else {
authMethods = getAuthMethods(globalSecurities, securitySchemes);
CodegenOperation codegenOperation = config.fromOperation(resourcePath, httpMethod, operation, path.getServers());
codegenOperation.tags = new ArrayList<>(tags);
config.addOperationToGroup(config.sanitizeTag(tag.getName()), resourcePath, operation, codegenOperation, operations);
List<SecurityRequirement> securities = operation.getSecurity();
if (securities != null && securities.isEmpty()) {
continue;
}
Map<String, SecurityScheme> authMethods = getAuthMethods(securities, securitySchemes);
if (authMethods != null && !authMethods.isEmpty()) {
List<CodegenSecurity> fullAuthMethods = config.fromSecurity(authMethods);
codegenOperation.authMethods = filterAuthMethods(fullAuthMethods, globalSecurities);
codegenOperation.authMethods = filterAuthMethods(fullAuthMethods, securities);
codegenOperation.hasAuthMethods = true;
} else {
authMethods = getAuthMethods(globalSecurities, securitySchemes);
if (authMethods != null && !authMethods.isEmpty()) {
List<CodegenSecurity> fullAuthMethods = config.fromSecurity(authMethods);
codegenOperation.authMethods = filterAuthMethods(fullAuthMethods, globalSecurities);
codegenOperation.hasAuthMethods = true;
}
}
}
} catch (Exception ex) {
String msg = "Could not process operation:\n" //
+ " Tag: " + tag + "\n"//
@@ -1527,7 +1532,6 @@ public class DefaultGenerator implements Generator {
throw new RuntimeException(msg, ex);
}
}
}
private static String generateParameterId(Parameter parameter) {

View File

@@ -96,6 +96,11 @@ public class OpenAPINormalizer {
// when set to true, normalize OpenAPI 3.1 spec to make it work with the generator
final String NORMALIZE_31SPEC = "NORMALIZE_31SPEC";
// when set to true, remove x-internal: true from models, operations
final String REMOVE_X_INTERNAL = "REMOVE_X_INTERNAL";
final String X_INTERNAL = "x-internal";
boolean removeXInternal;
// ============= end of rules =============
/**
@@ -125,6 +130,7 @@ public class OpenAPINormalizer {
ruleNames.add(ADD_UNSIGNED_TO_INTEGER_WITH_INVALID_MAX_VALUE);
ruleNames.add(REFACTOR_ALLOF_WITH_PROPERTIES_ONLY);
ruleNames.add(NORMALIZE_31SPEC);
ruleNames.add(REMOVE_X_INTERNAL);
// rules that are default to true
rules.put(SIMPLIFY_ONEOF_ANYOF, true);
@@ -224,7 +230,6 @@ public class OpenAPINormalizer {
normalizeParameters(path.getParameters());
for (Operation operation : operations) {
normalizeOperation(operation);
normalizeRequestBody(operation);
normalizeParameters(operation.getParameters());
@@ -239,6 +244,8 @@ public class OpenAPINormalizer {
* @param operation Operation
*/
private void normalizeOperation(Operation operation) {
processRemoveXInternalFromOperation(operation);
processKeepOnlyFirstTagInOperation(operation);
processSetTagsForAllOperations(operation);
@@ -372,8 +379,15 @@ public class OpenAPINormalizer {
if (schema == null) {
LOGGER.warn("{} not fount found in openapi/components/schemas.", schemaName);
} else {
Schema result = normalizeSchema(schema, new HashSet<>());
schemas.put(schemaName, result);
// remove x-internal if needed
if (schema.getExtensions() != null && getRule(REMOVE_X_INTERNAL)) {
if (Boolean.parseBoolean(String.valueOf(schema.getExtensions().get(X_INTERNAL)))) {
schema.getExtensions().remove(X_INTERNAL);
}
}
// normalize the schemas
schemas.put(schemaName, normalizeSchema(schema, new HashSet<>()));
}
}
}
@@ -605,6 +619,26 @@ public class OpenAPINormalizer {
}
}
/**
* Keep only first tag in the operation if the operation has more than
* one tag.
*
* @param operation Operation
*/
private void processRemoveXInternalFromOperation(Operation operation) {
if (!getRule(REMOVE_X_INTERNAL)) {
return;
}
if (operation.getExtensions() == null) {
return;
}
if (Boolean.parseBoolean(String.valueOf(operation.getExtensions().get("x-internal")))) {
operation.getExtensions().remove(X_INTERNAL);
}
}
/**
* Keep only first tag in the operation if the operation has more than
* one tag.

View File

@@ -400,7 +400,7 @@ public class OpenAPINormalizerTest {
Schema pet = openAPI.getComponents().getSchemas().get("Pet");
// verify schema for property id
Schema petSchema = (Schema)pet.getProperties().get("id");
Schema petSchema = (Schema) pet.getProperties().get("id");
// both type and types are defined
assertNotNull(petSchema.getType());
assertNotNull(petSchema.getTypes());
@@ -429,4 +429,24 @@ public class OpenAPINormalizerTest {
assertNotNull(pathItem.getDelete().getParameters().get(0).getSchema().getType());
assertNotNull(pathItem.getDelete().getParameters().get(0).getSchema().getTypes());
}
}
@Test
public void testRemoveXInternal() {
OpenAPI openAPI = TestUtils.parseSpec("src/test/resources/3_0/enableKeepOnlyFirstTagInOperation_test.yaml");
Schema s = openAPI.getComponents().getSchemas().get("Dummy");
assertEquals(openAPI.getPaths().get("/person/display/{personId}").getGet().getExtensions(), null);
assertEquals(openAPI.getPaths().get("/person/display/{personId}").getDelete().getExtensions().get("x-internal"), true);
assertEquals(s.getExtensions().get("x-internal"), true);
Map<String, String> options = new HashMap<>();
options.put("REMOVE_X_INTERNAL", "true");
OpenAPINormalizer openAPINormalizer = new OpenAPINormalizer(openAPI, options);
openAPINormalizer.normalize();
Schema s2 = openAPI.getComponents().getSchemas().get("Dummy");
assertEquals(openAPI.getPaths().get("/person/display/{personId}").getGet().getExtensions(), null);
assertEquals(openAPI.getPaths().get("/person/display/{personId}").getDelete().getExtensions().get("x-internal"), null);
assertEquals(s2.getExtensions().get("x-internal"), null);
}
}

View File

@@ -30,6 +30,7 @@ paths:
delete:
tags:
- person
x-internal: true
parameters:
- name: personId
in: path
@@ -57,3 +58,10 @@ components:
type: string
firstName:
type: string
Dummy:
x-internal: true
description: to test x-internal
type: object
properties:
test:
type: string

View File

@@ -160,7 +160,6 @@ Class | Method | HTTP request | Description
*UserApi* | [**logoutUser**](docs/UserApi.md#logoutUser) | **GET** /user/logout | Logs out current logged in user session
*UserApi* | [**updateUser**](docs/UserApi.md#updateUser) | **PUT** /user/{username} | Updated user
*ValuesApi* | [**getSomeValues**](docs/ValuesApi.md#getSomeValues) | **GET** /values | Get some primitive variable values
*ValuesApi* | [**internalOnlyGet**](docs/ValuesApi.md#internalOnlyGet) | **GET** /internal/only | internal only
## Documentation for Models

View File

@@ -5,7 +5,6 @@ All URIs are relative to *http://petstore.swagger.io:80/v2*
| Method | HTTP request | Description |
|------------- | ------------- | -------------|
| [**getSomeValues**](ValuesApi.md#getSomeValues) | **GET** /values | Get some primitive variable values |
| [**internalOnlyGet**](ValuesApi.md#internalOnlyGet) | **GET** /internal/only | internal only |
<a id="getSomeValues"></a>
@@ -67,62 +66,3 @@ No authorization required
| **200** | successful operation | - |
| **400** | Invalid Value | - |
<a id="internalOnlyGet"></a>
# **internalOnlyGet**
> Variable internalOnlyGet()
internal only
### Example
```java
// Import classes:
import org.openapitools.client.ApiClient;
import org.openapitools.client.ApiException;
import org.openapitools.client.Configuration;
import org.openapitools.client.models.*;
import org.openapitools.client.api.ValuesApi;
public class Example {
public static void main(String[] args) {
ApiClient defaultClient = Configuration.getDefaultApiClient();
defaultClient.setBasePath("http://petstore.swagger.io:80/v2");
ValuesApi apiInstance = new ValuesApi(defaultClient);
try {
Variable result = apiInstance.internalOnlyGet();
System.out.println(result);
} catch (ApiException e) {
System.err.println("Exception when calling ValuesApi#internalOnlyGet");
System.err.println("Status code: " + e.getCode());
System.err.println("Reason: " + e.getResponseBody());
System.err.println("Response headers: " + e.getResponseHeaders());
e.printStackTrace();
}
}
}
```
### Parameters
This endpoint does not need any parameter.
### Return type
[**Variable**](Variable.md)
### Authorization
No authorization required
### HTTP request headers
- **Content-Type**: Not defined
- **Accept**: application/json
### HTTP response details
| Status code | Description | Response headers |
|-------------|-------------|------------------|
| **200** | successful operation | - |
| **400** | Invalid Value | - |

View File

@@ -189,121 +189,4 @@ public class ValuesApi {
localVarApiClient.executeAsync(localVarCall, localVarReturnType, _callback);
return localVarCall;
}
/**
* Build call for internalOnlyGet
* @param _callback Callback for upload/download progress
* @return Call to execute
* @throws ApiException If fail to serialize the request body object
* @http.response.details
<table summary="Response Details" border="1">
<tr><td> Status Code </td><td> Description </td><td> Response Headers </td></tr>
<tr><td> 200 </td><td> successful operation </td><td> - </td></tr>
<tr><td> 400 </td><td> Invalid Value </td><td> - </td></tr>
</table>
*/
public okhttp3.Call internalOnlyGetCall(final ApiCallback _callback) throws ApiException {
String basePath = null;
// Operation Servers
String[] localBasePaths = new String[] { };
// Determine Base Path to Use
if (localCustomBaseUrl != null){
basePath = localCustomBaseUrl;
} else if ( localBasePaths.length > 0 ) {
basePath = localBasePaths[localHostIndex];
} else {
basePath = null;
}
Object localVarPostBody = null;
// create path and map variables
String localVarPath = "/internal/only";
List<Pair> localVarQueryParams = new ArrayList<Pair>();
List<Pair> localVarCollectionQueryParams = new ArrayList<Pair>();
Map<String, String> localVarHeaderParams = new HashMap<String, String>();
Map<String, String> localVarCookieParams = new HashMap<String, String>();
Map<String, Object> localVarFormParams = new HashMap<String, Object>();
final String[] localVarAccepts = {
"application/json"
};
final String localVarAccept = localVarApiClient.selectHeaderAccept(localVarAccepts);
if (localVarAccept != null) {
localVarHeaderParams.put("Accept", localVarAccept);
}
final String[] localVarContentTypes = {
};
final String localVarContentType = localVarApiClient.selectHeaderContentType(localVarContentTypes);
if (localVarContentType != null) {
localVarHeaderParams.put("Content-Type", localVarContentType);
}
String[] localVarAuthNames = new String[] { };
return localVarApiClient.buildCall(basePath, localVarPath, "GET", localVarQueryParams, localVarCollectionQueryParams, localVarPostBody, localVarHeaderParams, localVarCookieParams, localVarFormParams, localVarAuthNames, _callback);
}
@SuppressWarnings("rawtypes")
private okhttp3.Call internalOnlyGetValidateBeforeCall(final ApiCallback _callback) throws ApiException {
return internalOnlyGetCall(_callback);
}
/**
* internal only
*
* @return Variable
* @throws ApiException If fail to call the API, e.g. server error or cannot deserialize the response body
* @http.response.details
<table summary="Response Details" border="1">
<tr><td> Status Code </td><td> Description </td><td> Response Headers </td></tr>
<tr><td> 200 </td><td> successful operation </td><td> - </td></tr>
<tr><td> 400 </td><td> Invalid Value </td><td> - </td></tr>
</table>
*/
public Variable internalOnlyGet() throws ApiException {
ApiResponse<Variable> localVarResp = internalOnlyGetWithHttpInfo();
return localVarResp.getData();
}
/**
* internal only
*
* @return ApiResponse&lt;Variable&gt;
* @throws ApiException If fail to call the API, e.g. server error or cannot deserialize the response body
* @http.response.details
<table summary="Response Details" border="1">
<tr><td> Status Code </td><td> Description </td><td> Response Headers </td></tr>
<tr><td> 200 </td><td> successful operation </td><td> - </td></tr>
<tr><td> 400 </td><td> Invalid Value </td><td> - </td></tr>
</table>
*/
public ApiResponse<Variable> internalOnlyGetWithHttpInfo() throws ApiException {
okhttp3.Call localVarCall = internalOnlyGetValidateBeforeCall(null);
Type localVarReturnType = new TypeToken<Variable>(){}.getType();
return localVarApiClient.execute(localVarCall, localVarReturnType);
}
/**
* internal only (asynchronously)
*
* @param _callback The callback to be executed when the API call finishes
* @return The request call
* @throws ApiException If fail to process the API call, e.g. serializing the request body object
* @http.response.details
<table summary="Response Details" border="1">
<tr><td> Status Code </td><td> Description </td><td> Response Headers </td></tr>
<tr><td> 200 </td><td> successful operation </td><td> - </td></tr>
<tr><td> 400 </td><td> Invalid Value </td><td> - </td></tr>
</table>
*/
public okhttp3.Call internalOnlyGetAsync(final ApiCallback<Variable> _callback) throws ApiException {
okhttp3.Call localVarCall = internalOnlyGetValidateBeforeCall(_callback);
Type localVarReturnType = new TypeToken<Variable>(){}.getType();
localVarApiClient.executeAsync(localVarCall, localVarReturnType, _callback);
return localVarCall;
}
}