| = REST OpenApi Component |
| :doctitle: REST OpenApi |
| :shortname: rest-openapi |
| :artifactid: camel-rest-openapi |
| :description: Configure REST producers based on an OpenAPI specification document delegating to a component implementing the RestProducerFactory interface. |
| :since: 3.1 |
| :supportlevel: Stable |
| :tabs-sync-option: |
| :component-header: Only producer is supported |
| //Manually maintained attributes |
| :camel-spring-boot-name: rest-openapi |
| |
| |
| *Since Camel {since}* |
| |
| *{component-header}* |
| |
| The REST OpenApi* configures rest producers from |
| https://www.openapis.org/[OpenApi] (Open API) specification document and |
| delegates to a component implementing the _RestProducerFactory_ |
| interface. Currently known working components are: |
| |
| * xref:http-component.adoc[http] |
| * xref:netty-http-component.adoc[netty-http] |
| * xref:undertow-component.adoc[undertow] |
| * xref:vertx-http-component.adoc[vertx-http] |
| |
| Maven users will need to add the following dependency to their |
| `pom.xml` for this component: |
| |
| [source,xml] |
| ------------------------------------------------------------ |
| <dependency> |
| <groupId>org.apache.camel</groupId> |
| <artifactId>camel-rest-openapi</artifactId> |
| <version>x.x.x</version> |
| <!-- use the same version as your Camel core version --> |
| </dependency> |
| ------------------------------------------------------------ |
| |
| == URI format |
| |
| ------------------------------------------------------- |
| rest-openapi:[specificationPath#]operationId |
| ------------------------------------------------------- |
| |
| Where `operationId` is the ID of the operation in the OpenApi |
| specification, and `specificationPath` is the path to the |
| specification. |
| If the `specificationPath` is not specified it defaults to |
| `openapi.json`. The lookup mechanism uses Camels `ResourceHelper` to |
| load the resource, which means that you can use CLASSPATH resources |
| (`classpath:my-specification.json`), files |
| (`file:/some/path.json`), the web |
| (`\http://api.example.com/openapi.json`) or reference a bean |
| (`ref:nameOfBean`) or use a method of a bean |
| (`bean:nameOfBean.methodName`) to get the specification resource, |
| failing that OpenApi's own resource loading support. |
| |
| This component does not act as a HTTP client, it delegates that to |
| another component mentioned above. The lookup mechanism searches for a |
| single component that implements the _RestProducerFactory_ interface and |
| uses that. If the CLASSPATH contains more than one, then the property |
| `componentName` should be set to indicate which component to delegate |
| to. |
| |
| Most of the configuration is taken from the OpenApi specification but |
| the option exists to override those by specifying them on the component |
| or on the endpoint. Typically you would just need to override the |
| `host` or `basePath` if those differ from the specification. |
| |
| [NOTE] |
| ==== |
| The `host` parameter should contain the absolute URI containing |
| scheme, hostname and port number, for instance: |
| `\https://api.example.com` |
| ==== |
| |
| With `componentName` you specify what component is used to perform the |
| requests, this named component needs to be present in the Camel context |
| and implement the required _RestProducerFactory_ interface -- as do the |
| components listed at the top. |
| |
| If you do not specify the _componentName_ at either component or |
| endpoint level, CLASSPATH is searched for a suitable delegate. There |
| should be only one component present on the CLASSPATH that implements |
| the _RestProducerFactory_ interface for this to work. |
| |
| This component's endpoint URI is lenient which means that in addition |
| to message headers you can specify REST operation's parameters as |
| endpoint parameters, these will be constant for all subsequent |
| invocations so it makes sense to use this feature only for parameters |
| that are indeed constant for all invocations -- for example API version |
| in path such as `/api/\{version}/users/\{id}`. |
| |
| // component-configure options: START |
| |
| // component-configure options: END |
| |
| // component options: START |
| include::partial$component-configure-options.adoc[] |
| include::partial$component-endpoint-options.adoc[] |
| // component options: END |
| |
| // endpoint options: START |
| |
| // endpoint options: END |
| |
| |
| == Example: PetStore |
| |
| Checkout the `rest-openapi-simple` example project in |
| the https://github.com/apache/camel-spring-boot-examples repository. |
| |
| For example if you wanted to use the |
| https://petstore3.swagger.io/api/v3/[_PetStore_] provided REST API simply |
| reference the specification URI and desired operation id from the |
| OpenApi specification or download the specification and store it as |
| `openapi.json` (in the root) of CLASSPATH that way it will be |
| automatically used. Let's use the xref:http-component.adoc[HTTP] |
| component to perform all the requests and Camel's excellent support for |
| Spring Boot. |
| |
| Here are our dependencies defined in Maven POM file: |
| |
| [source,xml] |
| ---- |
| <dependency> |
| <groupId>org.apache.camel.springboot</groupId> |
| <artifactId>camel-http-starter</artifactId> |
| </dependency> |
| |
| <dependency> |
| <groupId>org.apache.camel.springboot</groupId> |
| <artifactId>camel-rest-openapi-starter</artifactId> |
| </dependency> |
| ---- |
| |
| Start by defining a _RestOpenApiComponent_ bean: |
| |
| [source,java] |
| ---- |
| @Bean |
| public Component petstore(CamelContext camelContext) { |
| RestOpenApiComponent petstore = new RestOpenApiComponent(camelContext); |
| petstore.setSpecificationUri(new URI("https://petstore3.swagger.io/api/v3/openapi.json")); |
| petstore.setHost("https://petstore3.swagger.io"); |
| return petstore; |
| } |
| ---- |
| |
| [NOTE] |
| ==== |
| Support in Camel for Spring Boot will auto create the |
| `HttpComponent` Spring bean, and you can configure it using |
| `application.properties` (or `application.yml`) using prefix |
| `camel.component.http.`. We are defining the `petstore` |
| component here in order to have a named component in the Camel context |
| that we can use to interact with the PetStore REST API, if this is the |
| only `rest-openapi` component used we might configure it in the same |
| manner (using `application.properties`). |
| |
| In this example, there is no need to explicitly associate the `petstore` |
| component with the `HttpComponent` as Camel will use the first class on |
| the CLASSPATH that implements `RestProducerFactory`. However, if a different |
| component is required, then calling `petstore.setComponentName("http")` |
| would use the named component from the Camel registry. |
| |
| ==== |
| |
| Now in our application we can simply use the `ProducerTemplate` to |
| invoke PetStore REST methods: |
| |
| [source,java] |
| ---- |
| @Autowired |
| ProducerTemplate template; |
| |
| String getPetJsonById(int petId) { |
| return template.requestBodyAndHeader("petstore:getPetById", null, "petId", petId); |
| } |
| ---- |
| |
| == Request validation |
| |
| API requests can be validated against the configured OpenAPI specification before they are sent by setting the `requestValidationEnabled` option to `true`. |
| Validation is provided by the https://bitbucket.org/atlassian/swagger-request-validator/src/master/[swagger-request-validator]. |
| |
| By default, the following checks are enabled and will cause request validation to fail if the requirements are not fulfilled. |
| |
| |=== |
| |Configuration key |Description |
| |
| |validation.request.body |
| |Validates the request body. If the content type of the request is `application/json`, the JSON content |
| will be validated against the schema defined in the OpenAPI specification. |
| |
| |validation.request.contentType.notAllowed |
| |Validates whether the `Content-Type` header for the request is valid for the API operation. |
| The value is taken from the `Content-Type` Camel message exchange header. |
| |
| |validation.request.path.missing |
| |Validates whether the resolved request path is valid for the API operation. |
| |
| |validation.request.parameter.header.missing |
| |Validates whether a HTTP header required by the API operation is present. The header is |
| expected to be present among the Camel message exchange headers. |
| |
| |validation.request.parameter.query.missing |
| |Validates whether a HTTP query parameter required by the API operation is present. The query parameter is |
| expected to be present among the Camel message exchange headers. |
| |=== |
| |
| If any of the validation checks fail, then a `RestOpenApiValidationException` is thrown. The exception object |
| has a `getValidationErrors` method that returns the error messages from the validator. |
| |
| === Customizing validation |
| |
| ==== Validation levels |
| |
| You can override the configuration options mentioned above and configure new ones via the `validationLevels` option. |
| You can configure additional options on the `rest-openapi` endpoint URI with options prefixed with `validation.`. |
| |
| For example, to disable the `validation.request.body` check and enable the `validation.request.body.unexpected` check. |
| |
| [source,java] |
| ---- |
| .to("rest-openapi#myOperation?validationEnabled=true&validation.request.body=IGNORE&validation.request.body.unexpected=ERROR") |
| ---- |
| |
| The full list of validation options can be found https://bitbucket.org/atlassian/swagger-request-validator/src/master/swagger-request-validator-core/src/main/resources/swagger/validation/messages.properties[here]. |
| |
| ==== RequestValidationCustomizer |
| |
| You can get complete control for the setup of the validation options with a custom `RequestValidationCustomizer`. For example. |
| |
| [source,java] |
| ---- |
| public class CustomRequestValidationCustomizer implements RequestValidationCustomizer { |
| @Override |
| public void customizeOpenApiInteractionValidator(OpenApiInteractionValidator.Builder builder) { |
| // Apply customizations to the OpenApiInteractionValidator builder |
| } |
| |
| @Override |
| public void customizeSimpleRequestBuilder( |
| SimpleRequest.Builder builder, RestOpenApiOperation openApiOperation, Exchange exchange) { |
| // Apply customizations to the SimpleRequest builder |
| } |
| } |
| ---- |
| |
| Assuming `CustomRequestValidationCustomizer` is bound to the Camel registry, you can reference it in the endpoint URI. |
| |
| [source,java] |
| ---- |
| .to("rest-openapi#myOperation?requestValidationEnabled=true&requestValidationCustomizer=#customRequestValidationCustomizer") |
| ---- |
| |
| include::spring-boot:partial$starter.adoc[] |