blob: 3279b49bb05f2bcc67ab7a869b8e365846486bd1 [file] [log] [blame]
= 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[]