= Vert.x OpenAPI
:toc: left

Vert.x OpenAPI extends Vert.x Web to support https://www.openapis.org/[OpenAPI 3], bringing to you a simple interface to build a Vert.x Web Router conforming your API contract.

Vert.x OpenAPI can:

* Parse and validate the your OpenAPI 3 contract
* Generate a router according to your spec, with correct path & methods
* Provide request parsing and validation based on your contract using https://vertx.io/docs/vertx-web-validation/java/[Vert.x Web Validation]
* Mount required security handlers
* Path conversion between OpenAPI style and Vert.x style
* Route requests to event bus using https://vertx.io/docs/vertx-web-api-service/java/[Vert.x Web API Service]

== Using Vert.x OpenAPI

To use Vert.x OpenAPI, add the following dependency to the _dependencies_ section of your build descriptor:

* Maven (in your `pom.xml`):

[source,xml,subs="+attributes"]
----
<dependency>
  <groupId>io.vertx</groupId>
  <artifactId>vertx-web-openapi</artifactId>
  <version>${maven.version}</version>
</dependency>
----

* Gradle (in your `build.gradle` file):

[source,groovy,subs="+attributes"]
----
dependencies {
  compile 'io.vertx:vertx-web-openapi:${maven.version}'
}
----

== `RouterBuilder`

{@link io.vertx.ext.web.openapi.RouterBuilder} is the main element of this module: It provides the interface to mount request handlers and generates the final {@link io.vertx.ext.web.Router}

To start using Vert.x Web OpenAPI, you must instantiate {@link io.vertx.ext.web.openapi.RouterBuilder} with your contract using
{@link io.vertx.ext.web.openapi.RouterBuilder#create(Vertx,String,Handler)}

For example to load a spec from the local filesystem:

[source,$lang]
----
{@link examples.OpenAPI3Examples#constructRouterBuilder}
----

You can construct a router builder from a remote spec:

[source,$lang]
----
{@link examples.OpenAPI3Examples#constructRouterBuilderFromUrl}
----

You can access a private remote spec configuring {@link io.vertx.ext.web.openapi.OpenAPILoaderOptions}:

[source,$lang]
----
{@link examples.OpenAPI3Examples#constructRouterBuilderFromUrlWithAuthenticationHeader}
----

You can modify different behaviours of the router builder with {@link io.vertx.ext.web.openapi.RouterBuilderOptions}:

[source,$lang]
----
{@link examples.OpenAPI3Examples#setOptions}
----

== Access to operations

To access to an https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.1.md#operationObject[Operation] defined in contract, use {@link io.vertx.ext.web.openapi.RouterBuilder#operation(String)}.
This method returns an {@link io.vertx.ext.web.openapi.Operation} instance that you can use to both access the model and assign handlers

To mount an handler to an operation use {@link io.vertx.ext.web.openapi.Operation#handler(io.vertx.core.Handler)},
to mount a failure handler use {@link io.vertx.ext.web.openapi.Operation#failureHandler(io.vertx.core.Handler)}

You can **add multiple handlers to same operation**, without overwrite the existing ones.

For example:

[source,$lang]
----
{@link examples.OpenAPI3Examples#addRoute}
----

[IMPORTANT]
====
You can't access to contract operations without `operationId`. The operations without `operationId` are ignored by the `RouterBuilder`
====

Vert.x OpenAPI mounts the correct {@link io.vertx.ext.web.validation.ValidationHandler} for you, so you can access to request parameters and request body.
Refer to https://vertx.io/docs/vertx-web-validation/java/[Vert.x Web Validation documentation] to learn how to get request parameters & request body and how to manage validation failures

== Configuring `AuthenticationHandler`s defined in the OpenAPI document

Security is a important aspect of any API. OpenAPI defines how security is expected to be enforced in the api document.

All security scheme information resided under the `/components/securitySchemes` component. The information in this
object is different and specific for each type of authentication. To avoid double configuration, this module allows you
to provide factories for authentication handlers that will receive the source configuration from the source document.

For example, given an document that defines `Basic Authentication` as follows:

----
openapi: 3.0.0
...
components:
  securitySchemes:
    basicAuth:     # <-- arbitrary name for the security scheme
      type: http
      scheme: basic
----

This can be configured with a factory as:

[source,$lang]
----
{@link examples.OpenAPI3Examples#authnFactoryBasic}
----

While this example is quite simple to configure, creating an authentication handler that requires the configuration
such as the API Key handler can extract the config:

----
  openapi: 3.0.0
  ...
  # 1) Define the key name and location
  components:
    securitySchemes:
      ApiKeyAuth:        # arbitrary name for the security scheme
        type: apiKey
        in: header       # can be "header", "query" or "cookie"
        name: X-API-KEY  # name of the header, query parameter or cookie
----

[source,$lang]
----
{@link examples.OpenAPI3Examples#authnFactoryApiKey}
----

Or you can configure more complex scenarios such as OpenId Connect which require server discovery.

----
openapi: 3.0.0
...
# 1) Define the security scheme type and attributes
components:
  securitySchemes:
    openId:   # <--- Arbitrary name for the security scheme. Used to refer to it from elsewhere.
      type: openIdConnect
      openIdConnectUrl: https://example.com/.well-known/openid-configuration
----

[source,$lang]
----
{@link examples.OpenAPI3Examples#authnFactoryOidc}
----

The API is designed to be fluent so it can be used in a short notation, for example:

[source,$lang]
----
{@link examples.OpenAPI3Examples#authnShort}
----

=== Blocking vs NonBlocking

From the examples above it is noticeable that handlers can be added in a blocking or not blocking way. The reason for
non blocking way usage is not just to support handlers like `OAuth2`. The non-blocking way can be useful for handlers
like JWT or basic authentication where the authentication provider requires loading of keys or configuration files.

Here is an example with JWT:

[source,$lang]
----
{@link examples.OpenAPI3Examples#authnAsyncJWT}
----


== Map `AuthenticationHandler` to OpenAPI security schemes

You have seen how you can map an {@link io.vertx.ext.web.handler.AuthenticationHandler} to a security schema defined in the contract. The previous examples are validating and will fail your route builder if the configuration is missing.

There could be cases where the contract is incomplete and you explicitly want to define security handlers. In this case
the API is slightly different and will not enforce any contract validation. Yet, the security handlers will be available
to the builder regardless.

For example, given your contract has a security schema named `security_scheme_name`:

[source,$lang]
----
{@link examples.OpenAPI3Examples#addSecurityHandler}
----

You can mount {@link io.vertx.ext.web.handler.AuthenticationHandler} included in Vert.x Web, for example:

[source,$lang]
----
{@link examples.OpenAPI3Examples#addJWT}
----

When you generate the {@link io.vertx.ext.web.Router} the router builder will solve the security schemes required for an operation.
It fails if there is a missing `AuthenticationHandler` required by a configured operation.

For debugging/testing purpose you can disable this check with {@link io.vertx.ext.web.openapi.RouterBuilderOptions#setRequireSecurityHandlers(boolean)}

== Not Implemented Error

Router builder automatically mounts a default handler for operations without a specified handler.
This default handler fails the routing context with 405 `Method Not Allowed`/501 `Not Implemented` error.
You can enable/disable it with {@link io.vertx.ext.web.openapi.RouterBuilderOptions#setMountNotImplementedHandler}
and you can customize this error handling with {@link io.vertx.ext.web.Router#errorHandler}

== Response Content Type Handler

Router builder automatically mounts a {@link io.vertx.ext.web.handler.ResponseContentTypeHandler} handler when contract requires it.
You can disable this feature with {@link io.vertx.ext.web.openapi.RouterBuilderOptions#setMountResponseContentTypeHandler}

== Operation model

If you need to access to your operation model while handling the request,
you can configure the router builder to push it inside the `RoutingContext` with {@link io.vertx.ext.web.openapi.RouterBuilderOptions#setOperationModelKey(String)}:

[source,$lang]
----
{@link examples.OpenAPI3Examples#addOperationModelKey}
----

== Body Handler

Router builder automatically mounts a {@link io.vertx.ext.web.handler.BodyHandler} to manage request bodies.
You can configure the instance of {@link io.vertx.ext.web.handler.BodyHandler} (e.g. to change upload directory) with {@link io.vertx.ext.web.openapi.RouterBuilder#bodyHandler(BodyHandler)}.

== `multipart/form-data` validation

The validation handler separates file uploads and form attributes as explained:

* If the parameter doesn't have an encoding associated field:
  - If the parameter has `type: string` and `format: base64` or `format: binary` is a file upload with content-type `application/octet-stream`
  - Otherwise is a form attribute
* If the parameter has the encoding associated field is a file upload

The form attributes are parsed, converted in json and validated,
while for file uploads the validation handler just checks the existence and the content type.

== Custom global handlers

If you need to mount handlers that must be executed for each operation in your router before the operation specific handlers, you can use {@link io.vertx.ext.web.openapi.RouterBuilder#rootHandler(Handler)}

== Router builder handlers mount order

Handlers are loaded by the router builder in this order:

1. Body handler
2. Custom global handlers
4. Configured {@link io.vertx.ext.web.handler.AuthenticationHandler}s
5. Generated {@link io.vertx.ext.web.validation.ValidationHandler}
6. User handlers or "Not implemented" handler (if enabled)

== Generate the router

When you are ready, generate the router and use it:

[source,$lang]
----
{@link examples.OpenAPI3Examples#generateRouter}
----

This method can fail with a {@link io.vertx.ext.web.openapi.RouterBuilderException}.

[TIP]
====
If you need to mount all the router generated by router builder under the same parent path, you can use {@link io.vertx.ext.web.Router#mountSubRouter(String, Router)}:

[source,$lang]
----
{@link examples.OpenAPI3Examples#subRouter}
----
====
