This is an automated email from the ASF dual-hosted git repository. davsclaus pushed a commit to branch openapi2 in repository https://gitbox.apache.org/repos/asf/camel.git
commit a41b4587d37a601611efc0019500dd1777c815b8 Author: Claus Ibsen <claus.ib...@gmail.com> AuthorDate: Mon Mar 25 12:48:57 2024 +0100 CAMEL-20557: Rest DSL to use openapi spec directly --- .../camel/catalog/components/rest-openapi.json | 54 +++++++++--------- .../vertx/PlatformHttpRestOpenApiConsumerTest.java | 65 +++++++++++++++++++++- .../openapi/RestOpenApiComponentConfigurer.java | 6 ++ .../openapi/RestOpenApiEndpointConfigurer.java | 6 ++ .../openapi/RestOpenApiEndpointUriFactory.java | 3 +- .../camel/component/rest/openapi/rest-openapi.json | 54 +++++++++--------- .../DefaultRestOpenapiProcessorStrategy.java | 63 +++++++++++++++++++++ .../rest/openapi/RestOpenApiComponent.java | 12 ++++ .../rest/openapi/RestOpenApiEndpoint.java | 11 ++++ .../rest/openapi/RestOpenApiProcessor.java | 8 ++- .../rest/openapi/RestOpenapiProcessorStrategy.java | 23 ++++++++ .../dsl/RestOpenApiEndpointBuilderFactory.java | 17 ++++++ .../camel/kotlin/components/RestOpenapiUriDsl.kt | 8 +++ 13 files changed, 272 insertions(+), 58 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 22998ee020e..fae90af3743 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 @@ -25,36 +25,38 @@ "componentProperties": { "requestValidationEnabled": { "index": 0, "kind": "property", "displayName": "Request Validation Enabled", "group": "common", "label": "", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Enable validation of requests against the configured OpenAPI specification" }, "bridgeErrorHandler": { "index": 1, "kind": "property", "displayName": "Bridge Error Handler", "group": "consumer", "label": "consumer", "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 messages, or the like [...] - "consumerComponentName": { "index": 2, "kind": "property", "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 interfac [...] - "restOpenapiProcessorStrategy": { "index": 3, "kind": "property", "displayName": "Rest Openapi Processor Strategy", "group": "consumer (advanced)", "label": "consumer,advanced", "required": false, "type": "object", "javaType": "org.apache.camel.component.rest.openapi.RestOpenapiProcessorStrategy", "deprecated": false, "autowired": false, "secret": false, "description": "To use a custom strategy for how to process Rest DSL requests" }, - "basePath": { "index": 4, "kind": "property", "displayName": "Base Path", "group": "producer", "label": "producer", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "API basePath, for example \/v2. Default is unset, if set overrides the value present in OpenApi specification." }, - "host": { "index": 5, "kind": "property", "displayName": "Host", "group": "producer", "label": "producer", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Scheme hostname and port to direct the HTTP requests to in the form of https:\/\/hostname:port. Can be configured at the endpoint, component or in the corresponding REST configuration in the Camel Context. If you give this component a nam [...] - "lazyStartProducer": { "index": 6, "kind": "property", "displayName": "Lazy Start Producer", "group": "producer", "label": "producer", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether the producer should be started lazy (on the first message). By starting lazy you can use this to allow CamelContext and routes to startup in situations where a producer may otherwise fail [...] - "specificationUri": { "index": 7, "kind": "property", "displayName": "Specification Uri", "group": "producer", "label": "producer", "required": false, "type": "string", "javaType": "java.net.URI", "deprecated": false, "autowired": false, "secret": false, "defaultValue": "openapi.json", "description": "Path to the OpenApi specification file. The scheme, host base path are taken from this specification, but these can be overridden with properties on the component or endpoint level. If [...] - "componentName": { "index": 8, "kind": "property", "displayName": "Component Name", "group": "producer (advanced)", "label": "producer,advanced", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Name of the Camel component that will perform the requests. The component must be present in Camel registry and it must implement RestProducerFactory service provider interface. If not set CLASSPATH [...] - "consumes": { "index": 9, "kind": "property", "displayName": "Consumes", "group": "producer (advanced)", "label": "producer,advanced", "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 val [...] - "produces": { "index": 10, "kind": "property", "displayName": "Produces", "group": "producer (advanced)", "label": "producer,advanced", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "What payload type this component is producing. For example application\/json according to the RFC7231. This equates to the value of Content-Type HTTP header. If set overrides any value present in the OpenApi s [...] - "autowiredEnabled": { "index": 11, "kind": "property", "displayName": "Autowired Enabled", "group": "advanced", "label": "advanced", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "description": "Whether autowiring is enabled. This is used for automatic autowiring options (the option must be marked as autowired) by looking up in the registry to find if there is a single instance of matching [...] - "requestValidationCustomizer": { "index": 12, "kind": "property", "displayName": "Request Validation Customizer", "group": "advanced", "label": "advanced", "required": false, "type": "object", "javaType": "org.apache.camel.component.rest.openapi.validator.RequestValidationCustomizer", "deprecated": false, "autowired": false, "secret": false, "description": "If request validation is enabled, this option provides the capability to customize the creation of OpenApiInteractionValidator u [...] - "sslContextParameters": { "index": 13, "kind": "property", "displayName": "Ssl Context Parameters", "group": "security", "label": "security", "required": false, "type": "object", "javaType": "org.apache.camel.support.jsse.SSLContextParameters", "deprecated": false, "autowired": false, "secret": false, "description": "Customize TLS parameters used by the component. If not set defaults to the TLS parameters set in the Camel context" }, - "useGlobalSslContextParameters": { "index": 14, "kind": "property", "displayName": "Use Global Ssl Context Parameters", "group": "security", "label": "security", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Enable usage of global SSL context parameters." } + "missingOperation": { "index": 2, "kind": "property", "displayName": "Missing Operation", "group": "consumer", "label": "consumer", "required": false, "type": "string", "javaType": "java.lang.String", "enum": [ "fail", "ignore", "dummy" ], "deprecated": false, "autowired": false, "secret": false, "defaultValue": "fail", "description": "Whether the consumer should fail,ignore or return a dummy response for OpenAPI operations that are not mapped to a corresponding route." }, + "consumerComponentName": { "index": 3, "kind": "property", "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 interfac [...] + "restOpenapiProcessorStrategy": { "index": 4, "kind": "property", "displayName": "Rest Openapi Processor Strategy", "group": "consumer (advanced)", "label": "consumer,advanced", "required": false, "type": "object", "javaType": "org.apache.camel.component.rest.openapi.RestOpenapiProcessorStrategy", "deprecated": false, "autowired": false, "secret": false, "description": "To use a custom strategy for how to process Rest DSL requests" }, + "basePath": { "index": 5, "kind": "property", "displayName": "Base Path", "group": "producer", "label": "producer", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "API basePath, for example \/v2. Default is unset, if set overrides the value present in OpenApi specification." }, + "host": { "index": 6, "kind": "property", "displayName": "Host", "group": "producer", "label": "producer", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Scheme hostname and port to direct the HTTP requests to in the form of https:\/\/hostname:port. Can be configured at the endpoint, component or in the corresponding REST configuration in the Camel Context. If you give this component a nam [...] + "lazyStartProducer": { "index": 7, "kind": "property", "displayName": "Lazy Start Producer", "group": "producer", "label": "producer", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether the producer should be started lazy (on the first message). By starting lazy you can use this to allow CamelContext and routes to startup in situations where a producer may otherwise fail [...] + "specificationUri": { "index": 8, "kind": "property", "displayName": "Specification Uri", "group": "producer", "label": "producer", "required": false, "type": "string", "javaType": "java.net.URI", "deprecated": false, "autowired": false, "secret": false, "defaultValue": "openapi.json", "description": "Path to the OpenApi specification file. The scheme, host base path are taken from this specification, but these can be overridden with properties on the component or endpoint level. If [...] + "componentName": { "index": 9, "kind": "property", "displayName": "Component Name", "group": "producer (advanced)", "label": "producer,advanced", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Name of the Camel component that will perform the requests. The component must be present in Camel registry and it must implement RestProducerFactory service provider interface. If not set CLASSPATH [...] + "consumes": { "index": 10, "kind": "property", "displayName": "Consumes", "group": "producer (advanced)", "label": "producer,advanced", "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 va [...] + "produces": { "index": 11, "kind": "property", "displayName": "Produces", "group": "producer (advanced)", "label": "producer,advanced", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "What payload type this component is producing. For example application\/json according to the RFC7231. This equates to the value of Content-Type HTTP header. If set overrides any value present in the OpenApi s [...] + "autowiredEnabled": { "index": 12, "kind": "property", "displayName": "Autowired Enabled", "group": "advanced", "label": "advanced", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "description": "Whether autowiring is enabled. This is used for automatic autowiring options (the option must be marked as autowired) by looking up in the registry to find if there is a single instance of matching [...] + "requestValidationCustomizer": { "index": 13, "kind": "property", "displayName": "Request Validation Customizer", "group": "advanced", "label": "advanced", "required": false, "type": "object", "javaType": "org.apache.camel.component.rest.openapi.validator.RequestValidationCustomizer", "deprecated": false, "autowired": false, "secret": false, "description": "If request validation is enabled, this option provides the capability to customize the creation of OpenApiInteractionValidator u [...] + "sslContextParameters": { "index": 14, "kind": "property", "displayName": "Ssl Context Parameters", "group": "security", "label": "security", "required": false, "type": "object", "javaType": "org.apache.camel.support.jsse.SSLContextParameters", "deprecated": false, "autowired": false, "secret": false, "description": "Customize TLS parameters used by the component. If not set defaults to the TLS parameters set in the Camel context" }, + "useGlobalSslContextParameters": { "index": 15, "kind": "property", "displayName": "Use Global Ssl Context Parameters", "group": "security", "label": "security", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Enable usage of global SSL context parameters." } }, "properties": { "specificationUri": { "index": 0, "kind": "path", "displayName": "Specification Uri", "group": "common", "label": "common", "required": false, "type": "string", "javaType": "java.net.URI", "deprecated": false, "autowired": false, "secret": false, "defaultValue": "openapi.json", "description": "Path to the OpenApi specification file. The scheme, host base path are taken from this specification, but these can be overridden with properties on the component or endpoint level. If not give [...] "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" }, "requestValidationEnabled": { "index": 2, "kind": "parameter", "displayName": "Request Validation Enabled", "group": "common", "label": "", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Enable validation of requests against the configured OpenAPI specification" }, - "bridgeErrorHandler": { "index": 3, "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": 4, "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 [...] - "exceptionHandler": { "index": 5, "kind": "parameter", "displayName": "Exception Handler", "group": "consumer (advanced)", "label": "consumer,advanced", "required": false, "type": "object", "javaType": "org.apache.camel.spi.ExceptionHandler", "optionalPrefix": "consumer.", "deprecated": false, "autowired": false, "secret": false, "description": "To let the consumer use a custom ExceptionHandler. Notice if the option bridgeErrorHandler is enabled then this option is not in use. By def [...] - "exchangePattern": { "index": 6, "kind": "parameter", "displayName": "Exchange Pattern", "group": "consumer (advanced)", "label": "consumer,advanced", "required": false, "type": "object", "javaType": "org.apache.camel.ExchangePattern", "enum": [ "InOnly", "InOut" ], "deprecated": false, "autowired": false, "secret": false, "description": "Sets the exchange pattern when the consumer creates an exchange." }, - "restOpenapiProcessorStrategy": { "index": 7, "kind": "parameter", "displayName": "Rest Openapi Processor Strategy", "group": "consumer (advanced)", "label": "consumer,advanced", "required": false, "type": "object", "javaType": "org.apache.camel.component.rest.openapi.RestOpenapiProcessorStrategy", "deprecated": false, "autowired": false, "secret": false, "description": "To use a custom strategy for how to process Rest DSL requests" }, - "basePath": { "index": 8, "kind": "parameter", "displayName": "Base Path", "group": "producer", "label": "producer", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "API basePath, for example \/v3. Default is unset, if set overrides the value present in OpenApi specification and in the component configuration." }, - "consumes": { "index": 9, "kind": "parameter", "displayName": "Consumes", "group": "producer", "label": "producer", "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 [...] - "host": { "index": 10, "kind": "parameter", "displayName": "Host", "group": "producer", "label": "producer", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Scheme hostname and port to direct the HTTP requests to in the form of https:\/\/hostname:port. Can be configured at the endpoint, component or in the corresponding REST configuration in the Camel Context. If you give this component a n [...] - "produces": { "index": 11, "kind": "parameter", "displayName": "Produces", "group": "producer", "label": "producer", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "What payload type this component is producing. For example application\/json according to the RFC7231. This equates to the value of Content-Type HTTP header. If set overrides any value present in the OpenApi specification. Overr [...] - "componentName": { "index": 12, "kind": "parameter", "displayName": "Component Name", "group": "producer (advanced)", "label": "producer,advanced", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Name of the Camel component that will perform the requests. The component must be present in Camel registry and it must implement RestProducerFactory service provider interface. If not set CLASSPAT [...] - "lazyStartProducer": { "index": 13, "kind": "parameter", "displayName": "Lazy Start Producer", "group": "producer (advanced)", "label": "producer,advanced", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether the producer should be started lazy (on the first message). By starting lazy you can use this to allow CamelContext and routes to startup in situations where a produ [...] - "requestValidationCustomizer": { "index": 14, "kind": "parameter", "displayName": "Request Validation Customizer", "group": "advanced", "label": "advanced", "required": false, "type": "object", "javaType": "org.apache.camel.component.rest.openapi.validator.RequestValidationCustomizer", "deprecated": false, "autowired": false, "secret": false, "description": "If request validation is enabled, this option provides the capability to customize the creation of OpenApiInteractionValidator [...] - "requestValidationLevels": { "index": 15, "kind": "parameter", "displayName": "Request Validation Levels", "group": "advanced", "label": "advanced", "required": false, "type": "object", "javaType": "java.util.Map<java.lang.String, java.lang.Object>", "prefix": "validation.", "multiValue": true, "deprecated": false, "autowired": false, "secret": false, "description": "Levels for specific OpenAPI request validation options. Multiple options can be specified as URI options prefixed by ' [...] + "missingOperation": { "index": 3, "kind": "parameter", "displayName": "Missing Operation", "group": "consumer", "label": "consumer", "required": false, "type": "string", "javaType": "java.lang.String", "enum": [ "fail", "ignore", "dummy" ], "deprecated": false, "autowired": false, "secret": false, "defaultValue": "fail", "description": "Whether the consumer should fail,ignore or return a dummy response for OpenAPI operations that are not mapped to a corresponding route." }, + "bridgeErrorHandler": { "index": 4, "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": 5, "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 [...] + "exceptionHandler": { "index": 6, "kind": "parameter", "displayName": "Exception Handler", "group": "consumer (advanced)", "label": "consumer,advanced", "required": false, "type": "object", "javaType": "org.apache.camel.spi.ExceptionHandler", "optionalPrefix": "consumer.", "deprecated": false, "autowired": false, "secret": false, "description": "To let the consumer use a custom ExceptionHandler. Notice if the option bridgeErrorHandler is enabled then this option is not in use. By def [...] + "exchangePattern": { "index": 7, "kind": "parameter", "displayName": "Exchange Pattern", "group": "consumer (advanced)", "label": "consumer,advanced", "required": false, "type": "object", "javaType": "org.apache.camel.ExchangePattern", "enum": [ "InOnly", "InOut" ], "deprecated": false, "autowired": false, "secret": false, "description": "Sets the exchange pattern when the consumer creates an exchange." }, + "restOpenapiProcessorStrategy": { "index": 8, "kind": "parameter", "displayName": "Rest Openapi Processor Strategy", "group": "consumer (advanced)", "label": "consumer,advanced", "required": false, "type": "object", "javaType": "org.apache.camel.component.rest.openapi.RestOpenapiProcessorStrategy", "deprecated": false, "autowired": false, "secret": false, "description": "To use a custom strategy for how to process Rest DSL requests" }, + "basePath": { "index": 9, "kind": "parameter", "displayName": "Base Path", "group": "producer", "label": "producer", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "API basePath, for example \/v3. Default is unset, if set overrides the value present in OpenApi specification and in the component configuration." }, + "consumes": { "index": 10, "kind": "parameter", "displayName": "Consumes", "group": "producer", "label": "producer", "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 [...] + "host": { "index": 11, "kind": "parameter", "displayName": "Host", "group": "producer", "label": "producer", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Scheme hostname and port to direct the HTTP requests to in the form of https:\/\/hostname:port. Can be configured at the endpoint, component or in the corresponding REST configuration in the Camel Context. If you give this component a n [...] + "produces": { "index": 12, "kind": "parameter", "displayName": "Produces", "group": "producer", "label": "producer", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "What payload type this component is producing. For example application\/json according to the RFC7231. This equates to the value of Content-Type HTTP header. If set overrides any value present in the OpenApi specification. Overr [...] + "componentName": { "index": 13, "kind": "parameter", "displayName": "Component Name", "group": "producer (advanced)", "label": "producer,advanced", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Name of the Camel component that will perform the requests. The component must be present in Camel registry and it must implement RestProducerFactory service provider interface. If not set CLASSPAT [...] + "lazyStartProducer": { "index": 14, "kind": "parameter", "displayName": "Lazy Start Producer", "group": "producer (advanced)", "label": "producer,advanced", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether the producer should be started lazy (on the first message). By starting lazy you can use this to allow CamelContext and routes to startup in situations where a produ [...] + "requestValidationCustomizer": { "index": 15, "kind": "parameter", "displayName": "Request Validation Customizer", "group": "advanced", "label": "advanced", "required": false, "type": "object", "javaType": "org.apache.camel.component.rest.openapi.validator.RequestValidationCustomizer", "deprecated": false, "autowired": false, "secret": false, "description": "If request validation is enabled, this option provides the capability to customize the creation of OpenApiInteractionValidator [...] + "requestValidationLevels": { "index": 16, "kind": "parameter", "displayName": "Request Validation Levels", "group": "advanced", "label": "advanced", "required": false, "type": "object", "javaType": "java.util.Map<java.lang.String, java.lang.Object>", "prefix": "validation.", "multiValue": true, "deprecated": false, "autowired": false, "secret": false, "description": "Levels for specific OpenAPI request validation options. Multiple options can be specified as URI options prefixed by ' [...] } } diff --git a/components/camel-platform-http-vertx/src/test/java/org/apache/camel/component/platform/http/vertx/PlatformHttpRestOpenApiConsumerTest.java b/components/camel-platform-http-vertx/src/test/java/org/apache/camel/component/platform/http/vertx/PlatformHttpRestOpenApiConsumerTest.java index 1ea0a976913..c41839ef21f 100644 --- a/components/camel-platform-http-vertx/src/test/java/org/apache/camel/component/platform/http/vertx/PlatformHttpRestOpenApiConsumerTest.java +++ b/components/camel-platform-http-vertx/src/test/java/org/apache/camel/component/platform/http/vertx/PlatformHttpRestOpenApiConsumerTest.java @@ -18,10 +18,12 @@ package org.apache.camel.component.platform.http.vertx; import org.apache.camel.CamelContext; import org.apache.camel.builder.RouteBuilder; +import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import static io.restassured.RestAssured.given; import static org.hamcrest.Matchers.equalTo; +import static org.junit.jupiter.api.Assertions.fail; public class PlatformHttpRestOpenApiConsumerTest { @@ -29,6 +31,37 @@ public class PlatformHttpRestOpenApiConsumerTest { public void testRestOpenApi() throws Exception { final CamelContext context = VertxPlatformHttpEngineTest.createCamelContext(); + try { + context.addRoutes(new RouteBuilder() { + @Override + public void configure() { + from("rest-openapi:classpath:openapi-v3.json?missingOperation=ignore") + .log("dummy"); + + from("direct:getPetById") + .setBody().constant("{\"pet\": \"tony the tiger\"}"); + } + }); + + context.start(); + + given() + .when() + .get("/api/v3/pet/123") + .then() + .statusCode(200) + .body(equalTo("{\"pet\": \"tony the tiger\"}")); + } finally { + context.stop(); + } + } + + @Test + public void testRestOpenApiDevMode() throws Exception { + final CamelContext context = VertxPlatformHttpEngineTest.createCamelContext(); + // run in developer mode + context.getCamelContextExtension().setProfile("dev"); + try { context.addRoutes(new RouteBuilder() { @Override @@ -54,6 +87,32 @@ public class PlatformHttpRestOpenApiConsumerTest { } } + @Test + public void testRestOpenApiMissingOperation() throws Exception { + final CamelContext context = VertxPlatformHttpEngineTest.createCamelContext(); + + try { + context.addRoutes(new RouteBuilder() { + @Override + public void configure() { + from("rest-openapi:classpath:openapi-v3.json?missingOperation=fail") + .log("dummy"); + + from("direct:getPetById") + .setBody().constant("{\"pet\": \"tony the tiger\"}"); + } + }); + + context.start(); + fail(); + } catch (IllegalArgumentException e) { + Assertions.assertTrue( + e.getMessage().startsWith("OpenAPI specification has 18 unmapped operations to corresponding routes")); + } finally { + context.stop(); + } + } + @Test public void testRestOpenApiNotFound() throws Exception { final CamelContext context = VertxPlatformHttpEngineTest.createCamelContext(); @@ -62,7 +121,7 @@ public class PlatformHttpRestOpenApiConsumerTest { context.addRoutes(new RouteBuilder() { @Override public void configure() { - from("rest-openapi:classpath:openapi-v3.json") + from("rest-openapi:classpath:openapi-v3.json?missingOperation=ignore") .log("dummy"); from("direct:getPetById") @@ -90,7 +149,7 @@ public class PlatformHttpRestOpenApiConsumerTest { context.addRoutes(new RouteBuilder() { @Override public void configure() { - from("rest-openapi:classpath:openapi-v3.json") + from("rest-openapi:classpath:openapi-v3.json?missingOperation=ignore") .log("dummy"); from("direct:getPetById") @@ -118,7 +177,7 @@ public class PlatformHttpRestOpenApiConsumerTest { context.addRoutes(new RouteBuilder() { @Override public void configure() { - from("rest-openapi:classpath:openapi-v3.json?requestValidationEnabled=true") + from("rest-openapi:classpath:openapi-v3.json?missingOperation=ignore&requestValidationEnabled=true") .log("dummy"); from("direct:updatePet") diff --git a/components/camel-rest-openapi/src/generated/java/org/apache/camel/component/rest/openapi/RestOpenApiComponentConfigurer.java b/components/camel-rest-openapi/src/generated/java/org/apache/camel/component/rest/openapi/RestOpenApiComponentConfigurer.java index 89b6cc3ccc6..96dd8f657ec 100644 --- a/components/camel-rest-openapi/src/generated/java/org/apache/camel/component/rest/openapi/RestOpenApiComponentConfigurer.java +++ b/components/camel-rest-openapi/src/generated/java/org/apache/camel/component/rest/openapi/RestOpenApiComponentConfigurer.java @@ -35,6 +35,8 @@ public class RestOpenApiComponentConfigurer extends PropertyConfigurerSupport im case "host": target.setHost(property(camelContext, java.lang.String.class, value)); return true; case "lazystartproducer": case "lazyStartProducer": target.setLazyStartProducer(property(camelContext, boolean.class, value)); return true; + case "missingoperation": + case "missingOperation": target.setMissingOperation(property(camelContext, java.lang.String.class, value)); return true; case "produces": target.setProduces(property(camelContext, java.lang.String.class, value)); return true; case "requestvalidationcustomizer": case "requestValidationCustomizer": target.setRequestValidationCustomizer(property(camelContext, org.apache.camel.component.rest.openapi.validator.RequestValidationCustomizer.class, value)); return true; @@ -69,6 +71,8 @@ public class RestOpenApiComponentConfigurer extends PropertyConfigurerSupport im case "host": return java.lang.String.class; case "lazystartproducer": case "lazyStartProducer": return boolean.class; + case "missingoperation": + case "missingOperation": return java.lang.String.class; case "produces": return java.lang.String.class; case "requestvalidationcustomizer": case "requestValidationCustomizer": return org.apache.camel.component.rest.openapi.validator.RequestValidationCustomizer.class; @@ -104,6 +108,8 @@ public class RestOpenApiComponentConfigurer extends PropertyConfigurerSupport im case "host": return target.getHost(); case "lazystartproducer": case "lazyStartProducer": return target.isLazyStartProducer(); + case "missingoperation": + case "missingOperation": return target.getMissingOperation(); case "produces": return target.getProduces(); case "requestvalidationcustomizer": case "requestValidationCustomizer": return target.getRequestValidationCustomizer(); diff --git a/components/camel-rest-openapi/src/generated/java/org/apache/camel/component/rest/openapi/RestOpenApiEndpointConfigurer.java b/components/camel-rest-openapi/src/generated/java/org/apache/camel/component/rest/openapi/RestOpenApiEndpointConfigurer.java index 7877105d046..6766a773f15 100644 --- a/components/camel-rest-openapi/src/generated/java/org/apache/camel/component/rest/openapi/RestOpenApiEndpointConfigurer.java +++ b/components/camel-rest-openapi/src/generated/java/org/apache/camel/component/rest/openapi/RestOpenApiEndpointConfigurer.java @@ -37,6 +37,8 @@ public class RestOpenApiEndpointConfigurer extends PropertyConfigurerSupport imp case "host": target.setHost(property(camelContext, java.lang.String.class, value)); return true; case "lazystartproducer": case "lazyStartProducer": target.setLazyStartProducer(property(camelContext, boolean.class, value)); return true; + case "missingoperation": + case "missingOperation": target.setMissingOperation(property(camelContext, java.lang.String.class, value)); return true; case "produces": target.setProduces(property(camelContext, java.lang.String.class, value)); return true; case "requestvalidationcustomizer": case "requestValidationCustomizer": target.setRequestValidationCustomizer(property(camelContext, org.apache.camel.component.rest.openapi.validator.RequestValidationCustomizer.class, value)); return true; @@ -69,6 +71,8 @@ public class RestOpenApiEndpointConfigurer extends PropertyConfigurerSupport imp case "host": return java.lang.String.class; case "lazystartproducer": case "lazyStartProducer": return boolean.class; + case "missingoperation": + case "missingOperation": return java.lang.String.class; case "produces": return java.lang.String.class; case "requestvalidationcustomizer": case "requestValidationCustomizer": return org.apache.camel.component.rest.openapi.validator.RequestValidationCustomizer.class; @@ -102,6 +106,8 @@ public class RestOpenApiEndpointConfigurer extends PropertyConfigurerSupport imp case "host": return target.getHost(); case "lazystartproducer": case "lazyStartProducer": return target.isLazyStartProducer(); + case "missingoperation": + case "missingOperation": return target.getMissingOperation(); case "produces": return target.getProduces(); case "requestvalidationcustomizer": case "requestValidationCustomizer": return target.getRequestValidationCustomizer(); diff --git a/components/camel-rest-openapi/src/generated/java/org/apache/camel/component/rest/openapi/RestOpenApiEndpointUriFactory.java b/components/camel-rest-openapi/src/generated/java/org/apache/camel/component/rest/openapi/RestOpenApiEndpointUriFactory.java index 1117c2366cf..f841c7ad9af 100644 --- a/components/camel-rest-openapi/src/generated/java/org/apache/camel/component/rest/openapi/RestOpenApiEndpointUriFactory.java +++ b/components/camel-rest-openapi/src/generated/java/org/apache/camel/component/rest/openapi/RestOpenApiEndpointUriFactory.java @@ -21,7 +21,7 @@ public class RestOpenApiEndpointUriFactory extends org.apache.camel.support.comp private static final Set<String> SECRET_PROPERTY_NAMES; private static final Set<String> MULTI_VALUE_PREFIXES; static { - Set<String> props = new HashSet<>(16); + Set<String> props = new HashSet<>(17); props.add("basePath"); props.add("bridgeErrorHandler"); props.add("componentName"); @@ -31,6 +31,7 @@ public class RestOpenApiEndpointUriFactory extends org.apache.camel.support.comp props.add("exchangePattern"); props.add("host"); props.add("lazyStartProducer"); + props.add("missingOperation"); props.add("operationId"); props.add("produces"); props.add("requestValidationCustomizer"); 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 22998ee020e..fae90af3743 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 @@ -25,36 +25,38 @@ "componentProperties": { "requestValidationEnabled": { "index": 0, "kind": "property", "displayName": "Request Validation Enabled", "group": "common", "label": "", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Enable validation of requests against the configured OpenAPI specification" }, "bridgeErrorHandler": { "index": 1, "kind": "property", "displayName": "Bridge Error Handler", "group": "consumer", "label": "consumer", "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 messages, or the like [...] - "consumerComponentName": { "index": 2, "kind": "property", "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 interfac [...] - "restOpenapiProcessorStrategy": { "index": 3, "kind": "property", "displayName": "Rest Openapi Processor Strategy", "group": "consumer (advanced)", "label": "consumer,advanced", "required": false, "type": "object", "javaType": "org.apache.camel.component.rest.openapi.RestOpenapiProcessorStrategy", "deprecated": false, "autowired": false, "secret": false, "description": "To use a custom strategy for how to process Rest DSL requests" }, - "basePath": { "index": 4, "kind": "property", "displayName": "Base Path", "group": "producer", "label": "producer", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "API basePath, for example \/v2. Default is unset, if set overrides the value present in OpenApi specification." }, - "host": { "index": 5, "kind": "property", "displayName": "Host", "group": "producer", "label": "producer", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Scheme hostname and port to direct the HTTP requests to in the form of https:\/\/hostname:port. Can be configured at the endpoint, component or in the corresponding REST configuration in the Camel Context. If you give this component a nam [...] - "lazyStartProducer": { "index": 6, "kind": "property", "displayName": "Lazy Start Producer", "group": "producer", "label": "producer", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether the producer should be started lazy (on the first message). By starting lazy you can use this to allow CamelContext and routes to startup in situations where a producer may otherwise fail [...] - "specificationUri": { "index": 7, "kind": "property", "displayName": "Specification Uri", "group": "producer", "label": "producer", "required": false, "type": "string", "javaType": "java.net.URI", "deprecated": false, "autowired": false, "secret": false, "defaultValue": "openapi.json", "description": "Path to the OpenApi specification file. The scheme, host base path are taken from this specification, but these can be overridden with properties on the component or endpoint level. If [...] - "componentName": { "index": 8, "kind": "property", "displayName": "Component Name", "group": "producer (advanced)", "label": "producer,advanced", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Name of the Camel component that will perform the requests. The component must be present in Camel registry and it must implement RestProducerFactory service provider interface. If not set CLASSPATH [...] - "consumes": { "index": 9, "kind": "property", "displayName": "Consumes", "group": "producer (advanced)", "label": "producer,advanced", "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 val [...] - "produces": { "index": 10, "kind": "property", "displayName": "Produces", "group": "producer (advanced)", "label": "producer,advanced", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "What payload type this component is producing. For example application\/json according to the RFC7231. This equates to the value of Content-Type HTTP header. If set overrides any value present in the OpenApi s [...] - "autowiredEnabled": { "index": 11, "kind": "property", "displayName": "Autowired Enabled", "group": "advanced", "label": "advanced", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "description": "Whether autowiring is enabled. This is used for automatic autowiring options (the option must be marked as autowired) by looking up in the registry to find if there is a single instance of matching [...] - "requestValidationCustomizer": { "index": 12, "kind": "property", "displayName": "Request Validation Customizer", "group": "advanced", "label": "advanced", "required": false, "type": "object", "javaType": "org.apache.camel.component.rest.openapi.validator.RequestValidationCustomizer", "deprecated": false, "autowired": false, "secret": false, "description": "If request validation is enabled, this option provides the capability to customize the creation of OpenApiInteractionValidator u [...] - "sslContextParameters": { "index": 13, "kind": "property", "displayName": "Ssl Context Parameters", "group": "security", "label": "security", "required": false, "type": "object", "javaType": "org.apache.camel.support.jsse.SSLContextParameters", "deprecated": false, "autowired": false, "secret": false, "description": "Customize TLS parameters used by the component. If not set defaults to the TLS parameters set in the Camel context" }, - "useGlobalSslContextParameters": { "index": 14, "kind": "property", "displayName": "Use Global Ssl Context Parameters", "group": "security", "label": "security", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Enable usage of global SSL context parameters." } + "missingOperation": { "index": 2, "kind": "property", "displayName": "Missing Operation", "group": "consumer", "label": "consumer", "required": false, "type": "string", "javaType": "java.lang.String", "enum": [ "fail", "ignore", "dummy" ], "deprecated": false, "autowired": false, "secret": false, "defaultValue": "fail", "description": "Whether the consumer should fail,ignore or return a dummy response for OpenAPI operations that are not mapped to a corresponding route." }, + "consumerComponentName": { "index": 3, "kind": "property", "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 interfac [...] + "restOpenapiProcessorStrategy": { "index": 4, "kind": "property", "displayName": "Rest Openapi Processor Strategy", "group": "consumer (advanced)", "label": "consumer,advanced", "required": false, "type": "object", "javaType": "org.apache.camel.component.rest.openapi.RestOpenapiProcessorStrategy", "deprecated": false, "autowired": false, "secret": false, "description": "To use a custom strategy for how to process Rest DSL requests" }, + "basePath": { "index": 5, "kind": "property", "displayName": "Base Path", "group": "producer", "label": "producer", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "API basePath, for example \/v2. Default is unset, if set overrides the value present in OpenApi specification." }, + "host": { "index": 6, "kind": "property", "displayName": "Host", "group": "producer", "label": "producer", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Scheme hostname and port to direct the HTTP requests to in the form of https:\/\/hostname:port. Can be configured at the endpoint, component or in the corresponding REST configuration in the Camel Context. If you give this component a nam [...] + "lazyStartProducer": { "index": 7, "kind": "property", "displayName": "Lazy Start Producer", "group": "producer", "label": "producer", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether the producer should be started lazy (on the first message). By starting lazy you can use this to allow CamelContext and routes to startup in situations where a producer may otherwise fail [...] + "specificationUri": { "index": 8, "kind": "property", "displayName": "Specification Uri", "group": "producer", "label": "producer", "required": false, "type": "string", "javaType": "java.net.URI", "deprecated": false, "autowired": false, "secret": false, "defaultValue": "openapi.json", "description": "Path to the OpenApi specification file. The scheme, host base path are taken from this specification, but these can be overridden with properties on the component or endpoint level. If [...] + "componentName": { "index": 9, "kind": "property", "displayName": "Component Name", "group": "producer (advanced)", "label": "producer,advanced", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Name of the Camel component that will perform the requests. The component must be present in Camel registry and it must implement RestProducerFactory service provider interface. If not set CLASSPATH [...] + "consumes": { "index": 10, "kind": "property", "displayName": "Consumes", "group": "producer (advanced)", "label": "producer,advanced", "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 va [...] + "produces": { "index": 11, "kind": "property", "displayName": "Produces", "group": "producer (advanced)", "label": "producer,advanced", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "What payload type this component is producing. For example application\/json according to the RFC7231. This equates to the value of Content-Type HTTP header. If set overrides any value present in the OpenApi s [...] + "autowiredEnabled": { "index": 12, "kind": "property", "displayName": "Autowired Enabled", "group": "advanced", "label": "advanced", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "description": "Whether autowiring is enabled. This is used for automatic autowiring options (the option must be marked as autowired) by looking up in the registry to find if there is a single instance of matching [...] + "requestValidationCustomizer": { "index": 13, "kind": "property", "displayName": "Request Validation Customizer", "group": "advanced", "label": "advanced", "required": false, "type": "object", "javaType": "org.apache.camel.component.rest.openapi.validator.RequestValidationCustomizer", "deprecated": false, "autowired": false, "secret": false, "description": "If request validation is enabled, this option provides the capability to customize the creation of OpenApiInteractionValidator u [...] + "sslContextParameters": { "index": 14, "kind": "property", "displayName": "Ssl Context Parameters", "group": "security", "label": "security", "required": false, "type": "object", "javaType": "org.apache.camel.support.jsse.SSLContextParameters", "deprecated": false, "autowired": false, "secret": false, "description": "Customize TLS parameters used by the component. If not set defaults to the TLS parameters set in the Camel context" }, + "useGlobalSslContextParameters": { "index": 15, "kind": "property", "displayName": "Use Global Ssl Context Parameters", "group": "security", "label": "security", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Enable usage of global SSL context parameters." } }, "properties": { "specificationUri": { "index": 0, "kind": "path", "displayName": "Specification Uri", "group": "common", "label": "common", "required": false, "type": "string", "javaType": "java.net.URI", "deprecated": false, "autowired": false, "secret": false, "defaultValue": "openapi.json", "description": "Path to the OpenApi specification file. The scheme, host base path are taken from this specification, but these can be overridden with properties on the component or endpoint level. If not give [...] "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" }, "requestValidationEnabled": { "index": 2, "kind": "parameter", "displayName": "Request Validation Enabled", "group": "common", "label": "", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Enable validation of requests against the configured OpenAPI specification" }, - "bridgeErrorHandler": { "index": 3, "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": 4, "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 [...] - "exceptionHandler": { "index": 5, "kind": "parameter", "displayName": "Exception Handler", "group": "consumer (advanced)", "label": "consumer,advanced", "required": false, "type": "object", "javaType": "org.apache.camel.spi.ExceptionHandler", "optionalPrefix": "consumer.", "deprecated": false, "autowired": false, "secret": false, "description": "To let the consumer use a custom ExceptionHandler. Notice if the option bridgeErrorHandler is enabled then this option is not in use. By def [...] - "exchangePattern": { "index": 6, "kind": "parameter", "displayName": "Exchange Pattern", "group": "consumer (advanced)", "label": "consumer,advanced", "required": false, "type": "object", "javaType": "org.apache.camel.ExchangePattern", "enum": [ "InOnly", "InOut" ], "deprecated": false, "autowired": false, "secret": false, "description": "Sets the exchange pattern when the consumer creates an exchange." }, - "restOpenapiProcessorStrategy": { "index": 7, "kind": "parameter", "displayName": "Rest Openapi Processor Strategy", "group": "consumer (advanced)", "label": "consumer,advanced", "required": false, "type": "object", "javaType": "org.apache.camel.component.rest.openapi.RestOpenapiProcessorStrategy", "deprecated": false, "autowired": false, "secret": false, "description": "To use a custom strategy for how to process Rest DSL requests" }, - "basePath": { "index": 8, "kind": "parameter", "displayName": "Base Path", "group": "producer", "label": "producer", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "API basePath, for example \/v3. Default is unset, if set overrides the value present in OpenApi specification and in the component configuration." }, - "consumes": { "index": 9, "kind": "parameter", "displayName": "Consumes", "group": "producer", "label": "producer", "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 [...] - "host": { "index": 10, "kind": "parameter", "displayName": "Host", "group": "producer", "label": "producer", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Scheme hostname and port to direct the HTTP requests to in the form of https:\/\/hostname:port. Can be configured at the endpoint, component or in the corresponding REST configuration in the Camel Context. If you give this component a n [...] - "produces": { "index": 11, "kind": "parameter", "displayName": "Produces", "group": "producer", "label": "producer", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "What payload type this component is producing. For example application\/json according to the RFC7231. This equates to the value of Content-Type HTTP header. If set overrides any value present in the OpenApi specification. Overr [...] - "componentName": { "index": 12, "kind": "parameter", "displayName": "Component Name", "group": "producer (advanced)", "label": "producer,advanced", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Name of the Camel component that will perform the requests. The component must be present in Camel registry and it must implement RestProducerFactory service provider interface. If not set CLASSPAT [...] - "lazyStartProducer": { "index": 13, "kind": "parameter", "displayName": "Lazy Start Producer", "group": "producer (advanced)", "label": "producer,advanced", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether the producer should be started lazy (on the first message). By starting lazy you can use this to allow CamelContext and routes to startup in situations where a produ [...] - "requestValidationCustomizer": { "index": 14, "kind": "parameter", "displayName": "Request Validation Customizer", "group": "advanced", "label": "advanced", "required": false, "type": "object", "javaType": "org.apache.camel.component.rest.openapi.validator.RequestValidationCustomizer", "deprecated": false, "autowired": false, "secret": false, "description": "If request validation is enabled, this option provides the capability to customize the creation of OpenApiInteractionValidator [...] - "requestValidationLevels": { "index": 15, "kind": "parameter", "displayName": "Request Validation Levels", "group": "advanced", "label": "advanced", "required": false, "type": "object", "javaType": "java.util.Map<java.lang.String, java.lang.Object>", "prefix": "validation.", "multiValue": true, "deprecated": false, "autowired": false, "secret": false, "description": "Levels for specific OpenAPI request validation options. Multiple options can be specified as URI options prefixed by ' [...] + "missingOperation": { "index": 3, "kind": "parameter", "displayName": "Missing Operation", "group": "consumer", "label": "consumer", "required": false, "type": "string", "javaType": "java.lang.String", "enum": [ "fail", "ignore", "dummy" ], "deprecated": false, "autowired": false, "secret": false, "defaultValue": "fail", "description": "Whether the consumer should fail,ignore or return a dummy response for OpenAPI operations that are not mapped to a corresponding route." }, + "bridgeErrorHandler": { "index": 4, "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": 5, "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 [...] + "exceptionHandler": { "index": 6, "kind": "parameter", "displayName": "Exception Handler", "group": "consumer (advanced)", "label": "consumer,advanced", "required": false, "type": "object", "javaType": "org.apache.camel.spi.ExceptionHandler", "optionalPrefix": "consumer.", "deprecated": false, "autowired": false, "secret": false, "description": "To let the consumer use a custom ExceptionHandler. Notice if the option bridgeErrorHandler is enabled then this option is not in use. By def [...] + "exchangePattern": { "index": 7, "kind": "parameter", "displayName": "Exchange Pattern", "group": "consumer (advanced)", "label": "consumer,advanced", "required": false, "type": "object", "javaType": "org.apache.camel.ExchangePattern", "enum": [ "InOnly", "InOut" ], "deprecated": false, "autowired": false, "secret": false, "description": "Sets the exchange pattern when the consumer creates an exchange." }, + "restOpenapiProcessorStrategy": { "index": 8, "kind": "parameter", "displayName": "Rest Openapi Processor Strategy", "group": "consumer (advanced)", "label": "consumer,advanced", "required": false, "type": "object", "javaType": "org.apache.camel.component.rest.openapi.RestOpenapiProcessorStrategy", "deprecated": false, "autowired": false, "secret": false, "description": "To use a custom strategy for how to process Rest DSL requests" }, + "basePath": { "index": 9, "kind": "parameter", "displayName": "Base Path", "group": "producer", "label": "producer", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "API basePath, for example \/v3. Default is unset, if set overrides the value present in OpenApi specification and in the component configuration." }, + "consumes": { "index": 10, "kind": "parameter", "displayName": "Consumes", "group": "producer", "label": "producer", "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 [...] + "host": { "index": 11, "kind": "parameter", "displayName": "Host", "group": "producer", "label": "producer", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Scheme hostname and port to direct the HTTP requests to in the form of https:\/\/hostname:port. Can be configured at the endpoint, component or in the corresponding REST configuration in the Camel Context. If you give this component a n [...] + "produces": { "index": 12, "kind": "parameter", "displayName": "Produces", "group": "producer", "label": "producer", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "What payload type this component is producing. For example application\/json according to the RFC7231. This equates to the value of Content-Type HTTP header. If set overrides any value present in the OpenApi specification. Overr [...] + "componentName": { "index": 13, "kind": "parameter", "displayName": "Component Name", "group": "producer (advanced)", "label": "producer,advanced", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Name of the Camel component that will perform the requests. The component must be present in Camel registry and it must implement RestProducerFactory service provider interface. If not set CLASSPAT [...] + "lazyStartProducer": { "index": 14, "kind": "parameter", "displayName": "Lazy Start Producer", "group": "producer (advanced)", "label": "producer,advanced", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether the producer should be started lazy (on the first message). By starting lazy you can use this to allow CamelContext and routes to startup in situations where a produ [...] + "requestValidationCustomizer": { "index": 15, "kind": "parameter", "displayName": "Request Validation Customizer", "group": "advanced", "label": "advanced", "required": false, "type": "object", "javaType": "org.apache.camel.component.rest.openapi.validator.RequestValidationCustomizer", "deprecated": false, "autowired": false, "secret": false, "description": "If request validation is enabled, this option provides the capability to customize the creation of OpenApiInteractionValidator [...] + "requestValidationLevels": { "index": 16, "kind": "parameter", "displayName": "Request Validation Levels", "group": "advanced", "label": "advanced", "required": false, "type": "object", "javaType": "java.util.Map<java.lang.String, java.lang.Object>", "prefix": "validation.", "multiValue": true, "deprecated": false, "autowired": false, "secret": false, "description": "Levels for specific OpenAPI request validation options. Multiple options can be specified as URI options prefixed by ' [...] } } 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 b46795d5a46..f150912331e 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 @@ -16,6 +16,11 @@ */ package org.apache.camel.component.rest.openapi; +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +import io.swagger.v3.oas.models.OpenAPI; import io.swagger.v3.oas.models.Operation; import org.apache.camel.AsyncCallback; import org.apache.camel.AsyncProducer; @@ -24,10 +29,13 @@ import org.apache.camel.CamelContextAware; import org.apache.camel.Endpoint; import org.apache.camel.Exchange; import org.apache.camel.NonManagedService; +import org.apache.camel.Route; import org.apache.camel.spi.ProducerCache; import org.apache.camel.support.cache.DefaultProducerCache; import org.apache.camel.support.service.ServiceHelper; import org.apache.camel.support.service.ServiceSupport; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * Default {@link RestOpenapiProcessorStrategy} that links the Rest DSL to routes called via direct:operationId. @@ -35,9 +43,50 @@ import org.apache.camel.support.service.ServiceSupport; public class DefaultRestOpenapiProcessorStrategy extends ServiceSupport implements RestOpenapiProcessorStrategy, CamelContextAware, NonManagedService { + private static final Logger LOG = LoggerFactory.getLogger(DefaultRestOpenapiProcessorStrategy.class); + private CamelContext camelContext; private ProducerCache producerCache; private String component = "direct"; + private String missingOperation; + + @Override + public void validateOpenApi(OpenAPI openAPI) throws Exception { + List<String> ids = new ArrayList<>(); + for (var e : openAPI.getPaths().entrySet()) { + for (var o : e.getValue().readOperations()) { + String id = o.getOperationId(); + ids.add(component + "://" + id); + } + } + // should have routes with all + List<String> existing = new ArrayList<>(); + for (Route route : camelContext.getRoutes()) { + String base = route.getEndpoint().getEndpointBaseUri(); + existing.add(base); + } + + // all ids must have a route + ids.removeAll(existing); + if (!ids.isEmpty()) { + String missing = ids.stream() + .sorted() + .map(id -> id.replace("://", ":")) + .collect(Collectors.joining("\n\t")); + String msg = String.format( + "OpenAPI specification has %d unmapped operations to corresponding routes: %n\t%s", + ids.size(), + missing); + + if ("fail".equalsIgnoreCase(missingOperation)) { + throw new IllegalArgumentException(msg); + } else if ("ignore".equalsIgnoreCase(missingOperation)) { + LOG.warn(msg + ". This validation error is ignored."); + } else if ("dev".equalsIgnoreCase(missingOperation)) { + LOG.warn(msg + ". This validation error is ignored when running in developer mode (profile=dev)."); + } + } + } @Override public boolean process(Operation operation, String path, Exchange exchange, AsyncCallback callback) { @@ -73,10 +122,24 @@ public class DefaultRestOpenapiProcessorStrategy extends ServiceSupport this.component = component; } + public String getMissingOperation() { + return missingOperation; + } + + public void setMissingOperation(String missingOperation) { + this.missingOperation = missingOperation; + } + @Override protected void doInit() throws Exception { producerCache = new DefaultProducerCache(this, getCamelContext(), 1000); ServiceHelper.initService(producerCache); + + // automatic adjust missing operation to fail, and ignore if you use developer mode + if (missingOperation == null) { + boolean dev = "dev".equalsIgnoreCase(camelContext.getCamelContextExtension().getProfile()); + missingOperation = dev ? "dev" : "fail"; + } } @Override diff --git a/components/camel-rest-openapi/src/main/java/org/apache/camel/component/rest/openapi/RestOpenApiComponent.java b/components/camel-rest-openapi/src/main/java/org/apache/camel/component/rest/openapi/RestOpenApiComponent.java index 98ea9e91fe4..e248acbc4aa 100644 --- a/components/camel-rest-openapi/src/main/java/org/apache/camel/component/rest/openapi/RestOpenApiComponent.java +++ b/components/camel-rest-openapi/src/main/java/org/apache/camel/component/rest/openapi/RestOpenApiComponent.java @@ -141,6 +141,9 @@ public final class RestOpenApiComponent extends DefaultComponent implements SSLC private SSLContextParameters sslContextParameters; @Metadata(description = "To use a custom strategy for how to process Rest DSL requests", label = "consumer,advanced") private RestOpenapiProcessorStrategy restOpenapiProcessorStrategy = new DefaultRestOpenapiProcessorStrategy(); + @Metadata(description = "Whether the consumer should fail,ignore or return a dummy response for OpenAPI operations that are not mapped to a corresponding route.", + enums = "fail,ignore,dummy", label = "consumer", defaultValue = "fail") + private String missingOperation; public RestOpenApiComponent() { } @@ -157,6 +160,7 @@ public final class RestOpenApiComponent extends DefaultComponent implements SSLC endpoint.setRequestValidationEnabled(isRequestValidationEnabled()); endpoint.setRequestValidationLevels(PropertiesHelper.extractProperties(parameters, "validation.")); endpoint.setRestOpenapiProcessorStrategy(getRestOpenapiProcessorStrategy()); + endpoint.setMissingOperation(getMissingOperation()); setProperties(endpoint, parameters); return endpoint; } @@ -206,6 +210,14 @@ public final class RestOpenApiComponent extends DefaultComponent implements SSLC this.restOpenapiProcessorStrategy = restOpenapiProcessorStrategy; } + public String getMissingOperation() { + return missingOperation; + } + + public void setMissingOperation(String missingOperation) { + this.missingOperation = missingOperation; + } + public void setBasePath(final String basePath) { this.basePath = notEmpty(basePath, "basePath"); } 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 2c55358dacf..9dbcd3df054 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 @@ -166,6 +166,9 @@ public final class RestOpenApiEndpoint extends DefaultEndpoint { private Map<String, Object> requestValidationLevels = new HashMap<>(); @UriParam(description = "To use a custom strategy for how to process Rest DSL requests", label = "consumer,advanced") private RestOpenapiProcessorStrategy restOpenapiProcessorStrategy; + @UriParam(description = "Whether the consumer should fail,ignore or return a dummy response for OpenAPI operations that are not mapped to a corresponding route.", + enums = "fail,ignore,dummy", label = "consumer", defaultValue = "fail") + private String missingOperation; public RestOpenApiEndpoint() { // help tooling instantiate endpoint @@ -447,6 +450,14 @@ public final class RestOpenApiEndpoint extends DefaultEndpoint { this.restOpenapiProcessorStrategy = restOpenapiProcessorStrategy; } + public String getMissingOperation() { + return missingOperation; + } + + public void setMissingOperation(String missingOperation) { + this.missingOperation = missingOperation; + } + Producer createProducerFor( final OpenAPI openapi, final Operation operation, final String method, final String uriTemplate) 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 39184eecadf..d7a6c0e50fa 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 @@ -141,6 +141,7 @@ public class RestOpenApiProcessor extends DelegateAsyncProcessor implements Came protected void doBuild() throws Exception { super.doBuild(); + CamelContextAware.trySetCamelContext(restOpenapiProcessorStrategy, getCamelContext()); // register all openapi paths for (var e : openAPI.getPaths().entrySet()) { String path = e.getKey(); // path @@ -149,15 +150,18 @@ public class RestOpenApiProcessor extends DelegateAsyncProcessor implements Came paths.add(new RestOpenApiConsumerPath(v, path, o.getValue())); } } - - CamelContextAware.trySetCamelContext(restOpenapiProcessorStrategy, getCamelContext()); ServiceHelper.buildService(restOpenapiProcessorStrategy); } @Override protected void doInit() throws Exception { super.doInit(); + + restOpenapiProcessorStrategy.setMissingOperation(endpoint.getMissingOperation()); ServiceHelper.initService(restOpenapiProcessorStrategy); + + // validate openapi contract + restOpenapiProcessorStrategy.validateOpenApi(openAPI); } @Override 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 80fb0501865..dcb1938dae2 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 @@ -16,6 +16,7 @@ */ package org.apache.camel.component.rest.openapi; +import io.swagger.v3.oas.models.OpenAPI; import io.swagger.v3.oas.models.Operation; import org.apache.camel.AsyncCallback; import org.apache.camel.Exchange; @@ -25,6 +26,28 @@ import org.apache.camel.Exchange; */ public interface RestOpenapiProcessorStrategy { + /** + * Whether the consumer should fail,ignore or return a dummy response for OpenAPI operations that are not mapped to + * a corresponding route. + */ + void setMissingOperation(String missingOperation); + + /** + * Whether the consumer should fail,ignore or return a dummy response for OpenAPI operations that are not mapped to + * a corresponding route. + */ + String getMissingOperation(); + + /** + * Validates the OpenAPI specification on startup + * + * @param openAPI the openapi specification + * @throws Exception is thrown if validation error on startup + */ + default void validateOpenApi(OpenAPI openAPI) throws Exception { + // noop + } + /** * Strategy for processing the Rest DSL operation * 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 10936800f56..d3545200a49 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 @@ -79,6 +79,23 @@ public interface RestOpenApiEndpointBuilderFactory { doSetProperty("requestValidationEnabled", requestValidationEnabled); return this; } + /** + * Whether the consumer should fail,ignore or return a dummy response + * for OpenAPI operations that are not mapped to a corresponding route. + * + * The option is a: <code>java.lang.String</code> type. + * + * Default: fail + * Group: consumer + * + * @param missingOperation the value to set + * @return the dsl builder + */ + default RestOpenApiEndpointConsumerBuilder missingOperation( + String missingOperation) { + doSetProperty("missingOperation", missingOperation); + return this; + } } /** 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 9827040e0b9..915720a83d6 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 @@ -83,6 +83,14 @@ public class RestOpenapiUriDsl( it.property("requestValidationEnabled", requestValidationEnabled.toString()) } + /** + * Whether the consumer should fail,ignore or return a dummy response for OpenAPI operations that + * are not mapped to a corresponding route. + */ + public fun missingOperation(missingOperation: String) { + it.property("missingOperation", missingOperation) + } + /** * 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 messages, or the