This is an automated email from the ASF dual-hosted git repository. davsclaus pushed a commit to branch vc4 in repository https://gitbox.apache.org/repos/asf/camel.git
commit 14f1b58af44e8a97fea86aa668129eed8ee143b5 Author: Claus Ibsen <claus.ib...@gmail.com> AuthorDate: Thu Jun 6 07:06:09 2024 +0200 CAMEL-20832: camel-openapi-validator to use Atlassian openapi validator for rest-dsl --- .../camel/catalog/components/rest-openapi.json | 2 +- .../client/OpenApiRestClientRequestValidator.java | 41 +++++++++++++++++++++- .../camel/component/rest/openapi/rest-openapi.json | 2 +- .../DefaultRestOpenapiProcessorStrategy.java | 3 +- .../rest/openapi/RestOpenApiEndpoint.java | 1 + .../rest/openapi/RestOpenApiProcessor.java | 2 +- .../rest/openapi/RestOpenapiProcessorStrategy.java | 3 +- .../org/apache/camel/ExchangeConstantProvider.java | 3 +- .../src/main/java/org/apache/camel/Exchange.java | 1 + .../camel/support/processor/RestBindingAdvice.java | 2 ++ .../dsl/RestOpenApiEndpointBuilderFactory.java | 8 +++-- .../camel/kotlin/components/RestOpenapiUriDsl.kt | 3 +- 12 files changed, 60 insertions(+), 11 deletions(-) diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/rest-openapi.json b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/rest-openapi.json index 32f5b67f650..f978b2d54e9 100644 --- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/rest-openapi.json +++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/rest-openapi.json @@ -48,7 +48,7 @@ "operationId": { "index": 1, "kind": "path", "displayName": "Operation Id", "group": "producer", "label": "producer", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "ID of the operation from the OpenApi specification. This is required when using producer" }, "apiContextPath": { "index": 2, "kind": "parameter", "displayName": "Api Context Path", "group": "consumer", "label": "consumer", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the context-path to use for servicing the OpenAPI specification" }, "clientRequestValidation": { "index": 3, "kind": "parameter", "displayName": "Client Request Validation", "group": "consumer", "label": "consumer", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether to enable validation of the client request to check if the incoming request is valid according to the OpenAPI specification" }, - "consumes": { "index": 4, "kind": "parameter", "displayName": "Consumes", "group": "consumer", "label": "consumer", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "What payload type this component capable of consuming. Could be one type, like application\/json or multiple types as application\/json, application\/xml; q=0.5 according to the RFC7231. This equates to the value of Accept HTTP h [...] + "consumes": { "index": 4, "kind": "parameter", "displayName": "Consumes", "group": "consumer", "label": "consumer", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "What payload type this component capable of consuming. Could be one type, like application\/json or multiple types as application\/json, application\/xml; q=0.5 according to the RFC7231. This equates or multiple types as applicat [...] "missingOperation": { "index": 5, "kind": "parameter", "displayName": "Missing Operation", "group": "consumer", "label": "consumer", "required": false, "type": "string", "javaType": "java.lang.String", "enum": [ "fail", "ignore", "mock" ], "deprecated": false, "autowired": false, "secret": false, "defaultValue": "fail", "description": "Whether the consumer should fail,ignore or return a mock response for OpenAPI operations that are not mapped to a corresponding route." }, "bridgeErrorHandler": { "index": 6, "kind": "parameter", "displayName": "Bridge Error Handler", "group": "consumer (advanced)", "label": "consumer,advanced", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Allows for bridging the consumer to the Camel routing Error Handler, which mean any exceptions (if possible) occurred while the Camel consumer is trying to pickup incoming [...] "consumerComponentName": { "index": 7, "kind": "parameter", "displayName": "Consumer Component Name", "group": "consumer (advanced)", "label": "consumer,advanced", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Name of the Camel component that will service the requests. The component must be present in Camel registry and it must implement RestOpenApiConsumerFactory service provider interfa [...] diff --git a/components/camel-openapi-validator/src/main/java/org/apache/camel/component/rest/openapi/validator/client/OpenApiRestClientRequestValidator.java b/components/camel-openapi-validator/src/main/java/org/apache/camel/component/rest/openapi/validator/client/OpenApiRestClientRequestValidator.java index 7c8c37fff76..989478c01e0 100644 --- a/components/camel-openapi-validator/src/main/java/org/apache/camel/component/rest/openapi/validator/client/OpenApiRestClientRequestValidator.java +++ b/components/camel-openapi-validator/src/main/java/org/apache/camel/component/rest/openapi/validator/client/OpenApiRestClientRequestValidator.java @@ -16,15 +16,54 @@ */ package org.apache.camel.component.rest.openapi.validator.client; +import com.atlassian.oai.validator.OpenApiInteractionValidator; +import com.atlassian.oai.validator.model.SimpleRequest; +import com.atlassian.oai.validator.report.ValidationReport; +import io.swagger.v3.oas.models.OpenAPI; import org.apache.camel.Exchange; import org.apache.camel.spi.RestClientRequestValidator; import org.apache.camel.spi.annotations.JdkService; +import org.apache.camel.support.ExchangeHelper; +import org.apache.camel.support.MessageHelper; @JdkService(RestClientRequestValidator.FACTORY) -public class OpenApiRestClientRequestValidator implements RestClientRequestValidator{ +public class OpenApiRestClientRequestValidator implements RestClientRequestValidator { + + // TODO: use default validator if no OpenAPI @Override public ValidationError validate(Exchange exchange, ValidationContext validationContent) { + OpenAPI openAPI = exchange.getProperty(Exchange.REST_OPENAPI, OpenAPI.class); + if (openAPI == null) { + return null; + } + + String method = exchange.getMessage().getHeader(Exchange.HTTP_METHOD, String.class); + String path = exchange.getMessage().getHeader(Exchange.HTTP_PATH, String.class); + String accept = exchange.getMessage().getHeader("Accept", String.class); + String contentType = ExchangeHelper.getContentType(exchange); + String body = MessageHelper.extractBodyAsString(exchange.getIn()); + + SimpleRequest.Builder builder = new SimpleRequest.Builder(method, path, false); + if (contentType != null) { + builder.withContentType(contentType); + } + if (accept != null) { + builder.withAccept(accept); + } + if (body != null) { + builder.withBody(body); + } + + Thread.currentThread().setContextClassLoader(exchange.getContext().getApplicationContextClassLoader()); + OpenApiInteractionValidator validator = OpenApiInteractionValidator.createFor(openAPI).build(); + ValidationReport report = validator.validateRequest(builder.build()); + if (report.hasErrors()) { + for (var m : report.getMessages()) { + System.out.println(m); + } + } return null; } + } diff --git a/components/camel-rest-openapi/src/generated/resources/META-INF/org/apache/camel/component/rest/openapi/rest-openapi.json b/components/camel-rest-openapi/src/generated/resources/META-INF/org/apache/camel/component/rest/openapi/rest-openapi.json index 32f5b67f650..f978b2d54e9 100644 --- a/components/camel-rest-openapi/src/generated/resources/META-INF/org/apache/camel/component/rest/openapi/rest-openapi.json +++ b/components/camel-rest-openapi/src/generated/resources/META-INF/org/apache/camel/component/rest/openapi/rest-openapi.json @@ -48,7 +48,7 @@ "operationId": { "index": 1, "kind": "path", "displayName": "Operation Id", "group": "producer", "label": "producer", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "ID of the operation from the OpenApi specification. This is required when using producer" }, "apiContextPath": { "index": 2, "kind": "parameter", "displayName": "Api Context Path", "group": "consumer", "label": "consumer", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the context-path to use for servicing the OpenAPI specification" }, "clientRequestValidation": { "index": 3, "kind": "parameter", "displayName": "Client Request Validation", "group": "consumer", "label": "consumer", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether to enable validation of the client request to check if the incoming request is valid according to the OpenAPI specification" }, - "consumes": { "index": 4, "kind": "parameter", "displayName": "Consumes", "group": "consumer", "label": "consumer", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "What payload type this component capable of consuming. Could be one type, like application\/json or multiple types as application\/json, application\/xml; q=0.5 according to the RFC7231. This equates to the value of Accept HTTP h [...] + "consumes": { "index": 4, "kind": "parameter", "displayName": "Consumes", "group": "consumer", "label": "consumer", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "What payload type this component capable of consuming. Could be one type, like application\/json or multiple types as application\/json, application\/xml; q=0.5 according to the RFC7231. This equates or multiple types as applicat [...] "missingOperation": { "index": 5, "kind": "parameter", "displayName": "Missing Operation", "group": "consumer", "label": "consumer", "required": false, "type": "string", "javaType": "java.lang.String", "enum": [ "fail", "ignore", "mock" ], "deprecated": false, "autowired": false, "secret": false, "defaultValue": "fail", "description": "Whether the consumer should fail,ignore or return a mock response for OpenAPI operations that are not mapped to a corresponding route." }, "bridgeErrorHandler": { "index": 6, "kind": "parameter", "displayName": "Bridge Error Handler", "group": "consumer (advanced)", "label": "consumer,advanced", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Allows for bridging the consumer to the Camel routing Error Handler, which mean any exceptions (if possible) occurred while the Camel consumer is trying to pickup incoming [...] "consumerComponentName": { "index": 7, "kind": "parameter", "displayName": "Consumer Component Name", "group": "consumer (advanced)", "label": "consumer,advanced", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Name of the Camel component that will service the requests. The component must be present in Camel registry and it must implement RestOpenApiConsumerFactory service provider interfa [...] diff --git a/components/camel-rest-openapi/src/main/java/org/apache/camel/component/rest/openapi/DefaultRestOpenapiProcessorStrategy.java b/components/camel-rest-openapi/src/main/java/org/apache/camel/component/rest/openapi/DefaultRestOpenapiProcessorStrategy.java index e0bff0f9672..d023b7b43b8 100644 --- a/components/camel-rest-openapi/src/main/java/org/apache/camel/component/rest/openapi/DefaultRestOpenapiProcessorStrategy.java +++ b/components/camel-rest-openapi/src/main/java/org/apache/camel/component/rest/openapi/DefaultRestOpenapiProcessorStrategy.java @@ -169,7 +169,7 @@ public class DefaultRestOpenapiProcessorStrategy extends ServiceSupport } @Override - public boolean process( + public boolean process(OpenAPI openAPI, Operation operation, String verb, String path, RestBindingAdvice binding, Exchange exchange, AsyncCallback callback) { @@ -190,6 +190,7 @@ public class DefaultRestOpenapiProcessorStrategy extends ServiceSupport // there is a route so process Map<String, Object> state; try { + exchange.setProperty(Exchange.REST_OPENAPI, openAPI); state = binding.before(exchange); } catch (Exception e) { exchange.setException(e); diff --git a/components/camel-rest-openapi/src/main/java/org/apache/camel/component/rest/openapi/RestOpenApiEndpoint.java b/components/camel-rest-openapi/src/main/java/org/apache/camel/component/rest/openapi/RestOpenApiEndpoint.java index dee36ced6a1..f7780434237 100644 --- a/components/camel-rest-openapi/src/main/java/org/apache/camel/component/rest/openapi/RestOpenApiEndpoint.java +++ b/components/camel-rest-openapi/src/main/java/org/apache/camel/component/rest/openapi/RestOpenApiEndpoint.java @@ -128,6 +128,7 @@ public final class RestOpenApiEndpoint extends DefaultEndpoint { label = "producer") private String operationId; @UriParam(description = "What payload type this component capable of consuming. Could be one type, like `application/json`" + + " or multiple types as `application/json, application/xml; q=0.5` according to the RFC7231. This equates" + " or multiple types as `application/json, application/xml; q=0.5` according to the RFC7231. This equates" + " to the value of `Accept` HTTP header. If set overrides any value found in the OpenApi specification and." + " in the component configuration", diff --git a/components/camel-rest-openapi/src/main/java/org/apache/camel/component/rest/openapi/RestOpenApiProcessor.java b/components/camel-rest-openapi/src/main/java/org/apache/camel/component/rest/openapi/RestOpenApiProcessor.java index 8304028d1eb..d9873587b2f 100644 --- a/components/camel-rest-openapi/src/main/java/org/apache/camel/component/rest/openapi/RestOpenApiProcessor.java +++ b/components/camel-rest-openapi/src/main/java/org/apache/camel/component/rest/openapi/RestOpenApiProcessor.java @@ -123,7 +123,7 @@ public class RestOpenApiProcessor extends DelegateAsyncProcessor implements Came HttpHelper.evalPlaceholders(exchange.getMessage().getHeaders(), uri, rcp.getConsumerPath()); // process the incoming request - return restOpenapiProcessorStrategy.process(o, verb, uri, rcp.getBinding(), exchange, callback); + return restOpenapiProcessorStrategy.process(openAPI, o, verb, uri, rcp.getBinding(), exchange, callback); } // is it the api-context path diff --git a/components/camel-rest-openapi/src/main/java/org/apache/camel/component/rest/openapi/RestOpenapiProcessorStrategy.java b/components/camel-rest-openapi/src/main/java/org/apache/camel/component/rest/openapi/RestOpenapiProcessorStrategy.java index 52c71a7c671..d93d0a79557 100644 --- a/components/camel-rest-openapi/src/main/java/org/apache/camel/component/rest/openapi/RestOpenapiProcessorStrategy.java +++ b/components/camel-rest-openapi/src/main/java/org/apache/camel/component/rest/openapi/RestOpenapiProcessorStrategy.java @@ -66,6 +66,7 @@ public interface RestOpenapiProcessorStrategy { /** * Strategy for processing the Rest DSL operation * + * @param openAPI the openapi specification * @param operation the rest operation * @param verb the HTTP verb (GET, POST etc.) * @param path the context-path @@ -77,7 +78,7 @@ public interface RestOpenapiProcessorStrategy { * @return (doneSync) true to continue execute synchronously, false to continue being executed * asynchronously */ - boolean process( + boolean process(OpenAPI openAPI, Operation operation, String verb, String path, RestBindingAdvice binding, Exchange exchange, AsyncCallback callback); diff --git a/core/camel-api/src/generated/java/org/apache/camel/ExchangeConstantProvider.java b/core/camel-api/src/generated/java/org/apache/camel/ExchangeConstantProvider.java index a97e9e8fc89..1887de93403 100644 --- a/core/camel-api/src/generated/java/org/apache/camel/ExchangeConstantProvider.java +++ b/core/camel-api/src/generated/java/org/apache/camel/ExchangeConstantProvider.java @@ -13,7 +13,7 @@ public class ExchangeConstantProvider { private static final Map<String, String> MAP; static { - Map<String, String> map = new HashMap<>(155); + Map<String, String> map = new HashMap<>(156); map.put("ACCEPT_CONTENT_TYPE", "CamelAcceptContentType"); map.put("AGGREGATED_COLLECTION_GUARD", "CamelAggregatedCollectionGuard"); map.put("AGGREGATED_COMPLETED_BY", "CamelAggregatedCompletedBy"); @@ -132,6 +132,7 @@ public class ExchangeConstantProvider { map.put("REDELIVERY_MAX_COUNTER", "CamelRedeliveryMaxCounter"); map.put("REST_HTTP_QUERY", "CamelRestHttpQuery"); map.put("REST_HTTP_URI", "CamelRestHttpUri"); + map.put("REST_OPENAPI", "CamelRestOpenAPI"); map.put("REUSE_SCRIPT_ENGINE", "CamelReuseScripteEngine"); map.put("ROLLBACK_ONLY", "CamelRollbackOnly"); map.put("ROLLBACK_ONLY_LAST", "CamelRollbackOnlyLast"); diff --git a/core/camel-api/src/main/java/org/apache/camel/Exchange.java b/core/camel-api/src/main/java/org/apache/camel/Exchange.java index 13cda74cb76..82d256b5f2d 100644 --- a/core/camel-api/src/main/java/org/apache/camel/Exchange.java +++ b/core/camel-api/src/main/java/org/apache/camel/Exchange.java @@ -260,6 +260,7 @@ public interface Exchange extends VariableAware { String REDELIVERY_DELAY = "CamelRedeliveryDelay"; String REST_HTTP_URI = "CamelRestHttpUri"; String REST_HTTP_QUERY = "CamelRestHttpQuery"; + String REST_OPENAPI = "CamelRestOpenAPI"; @Deprecated(since = "3.1.0") String ROLLBACK_ONLY = "CamelRollbackOnly"; @Deprecated(since = "3.1.0") diff --git a/core/camel-support/src/main/java/org/apache/camel/support/processor/RestBindingAdvice.java b/core/camel-support/src/main/java/org/apache/camel/support/processor/RestBindingAdvice.java index 32b5bc27775..93e76403335 100644 --- a/core/camel-support/src/main/java/org/apache/camel/support/processor/RestBindingAdvice.java +++ b/core/camel-support/src/main/java/org/apache/camel/support/processor/RestBindingAdvice.java @@ -16,6 +16,8 @@ */ package org.apache.camel.support.processor; +import java.util.Collection; +import java.util.Collections; import java.util.HashMap; import java.util.Locale; import java.util.Map; diff --git a/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/RestOpenApiEndpointBuilderFactory.java b/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/RestOpenApiEndpointBuilderFactory.java index 44adbafbbed..70173163f09 100644 --- a/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/RestOpenApiEndpointBuilderFactory.java +++ b/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/RestOpenApiEndpointBuilderFactory.java @@ -92,9 +92,11 @@ public interface RestOpenApiEndpointBuilderFactory { /** * What payload type this component capable of consuming. Could be one * type, like application/json or multiple types as application/json, - * application/xml; q=0.5 according to the RFC7231. This equates to the - * value of Accept HTTP header. If set overrides any value found in the - * OpenApi specification and. in the component configuration. + * application/xml; q=0.5 according to the RFC7231. This equates or + * multiple types as application/json, application/xml; q=0.5 according + * to the RFC7231. This equates to the value of Accept HTTP header. If + * set overrides any value found in the OpenApi specification and. in + * the component configuration. * * The option is a: <code>java.lang.String</code> type. * diff --git a/dsl/camel-kotlin-api/src/generated/kotlin/org/apache/camel/kotlin/components/RestOpenapiUriDsl.kt b/dsl/camel-kotlin-api/src/generated/kotlin/org/apache/camel/kotlin/components/RestOpenapiUriDsl.kt index 8aa50678a4a..6d209ef1058 100644 --- a/dsl/camel-kotlin-api/src/generated/kotlin/org/apache/camel/kotlin/components/RestOpenapiUriDsl.kt +++ b/dsl/camel-kotlin-api/src/generated/kotlin/org/apache/camel/kotlin/components/RestOpenapiUriDsl.kt @@ -95,7 +95,8 @@ public class RestOpenapiUriDsl( /** * What payload type this component capable of consuming. Could be one type, like application/json * or multiple types as application/json, application/xml; q=0.5 according to the RFC7231. This - * equates to the value of Accept HTTP header. If set overrides any value found in the OpenApi + * equates or multiple types as application/json, application/xml; q=0.5 according to the RFC7231. + * This equates to the value of Accept HTTP header. If set overrides any value found in the OpenApi * specification and. in the component configuration */ public fun consumes(consumes: String) {