# Vert.x OpenAPI

Vert.x OpenAPI extends Vert.x Web to support 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 Vert.x Web Validation

- Mount required security handlers

- Path conversion between OpenAPI style and Vert.x style

- Route requests to event bus using 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`):

    <dependency>
     <groupId>io.vertx</groupId>
     <artifactId>vertx-web-openapi</artifactId>
     <version>4.0.0.Beta3</version>
    </dependency>

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

    dependencies {
     compile 'io.vertx:vertx-web-openapi:4.0.0.Beta3'
    }

## `RouterFactory`

`RouterFactory` is the main element of this module: It provides the interface to mount request handlers and generates the final `Router`

To start using Vert.x Web OpenAPI, you must instantiate `RouterFactory` with your contract using `RouterFactory.create`

For example to load a spec from the local filesystem:

    RouterFactory.create(vertx, "src/main/resources/petstore.yaml", ar -> {
      if (ar.succeeded()) {
        // Spec loaded with success
        RouterFactory routerFactory = ar.result();
      } else {
        // Something went wrong during router factory initialization
        Throwable exception = ar.cause();
      }
    });

You can construct a router factory from a remote spec:

    RouterFactory.create(
      vertx,
      "https://raw.githubusercontent.com/OAI/OpenAPI-Specification/master/examples/v3.0/petstore.yaml",
      ar -> {
        if (ar.succeeded()) {
          // Spec loaded with success
          RouterFactory routerFactory = ar.result();
        } else {
          // Something went wrong during router factory initialization
          Throwable exception = ar.cause();
        }
      });

You can access a private remote spec configuring `OpenAPILoaderOptions`:

    OpenAPILoaderOptions loaderOptions = new OpenAPILoaderOptions()
      .putAuthHeader("Authorization", "Bearer xx.yy.zz");
    RouterFactory.create(
      vertx,
      "https://raw.githubusercontent.com/OAI/OpenAPI-Specification/master/examples/v3.0/petstore.yaml",
      loaderOptions,
      ar -> {
        if (ar.succeeded()) {
          // Spec loaded with success
          RouterFactory routerFactory = ar.result();
        } else {
          // Something went wrong during router factory initialization
          Throwable exception = ar.cause();
        }
      });

You can modify different behaviours of the router factory with `RouterFactoryOptions`:

    routerFactory.setOptions(new RouterFactoryOptions());

## Access to operations

To access to an Operation defined in contract, use `operation`. This method returns an `Operation` instance that you can use to both access the model and assign handlers

To mount an handler to an operation use `handler`, to mount a failure handler use `failureHandler`

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

For example:

    routerFactory
      .operation("awesomeOperation")
      .handler(routingContext -> {
        RequestParameters params = routingContext.get(ValidationHandler.REQUEST_CONTEXT_KEY);
        RequestParameter body = params.body();
        JsonObject jsonBody = body.getJsonObject();
        // Do something with body
      }).failureHandler(routingContext -> {
        // Handle failure
      });

Important | You can’t access to contract operations without `operationId`. The operations without `operationId` are ignored by the `RouterFactory`

Vert.x OpenAPI mounts the correct `ValidationHandler` for you, so you can access to request parameters and request body. Refer to Vert.x Web Validation documentation to learn how to get request parameters & request body and how to manage validation failures

## Map `AuthenticationHandler` to OpenAPI security schemes

You can map an `AuthenticationHandler` to a security schema defined in the contract.

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

    routerFactory.securityHandler("security_scheme_name", authenticationHandler);

You can mount `AuthenticationHandler` included in Vert.x Web, for example:

    routerFactory.securityHandler("jwt_auth", JWTAuthHandler.create(jwtAuthProvider));

When you generate the `Router` the router factory 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 `setRequireSecurityHandlers`

## Not Implemented Error

Router Factory 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 `setMountNotImplementedHandler` and you can customize this error handling with `errorHandler`

## Response Content Type Handler

Router Factory automatically mounts a `ResponseContentTypeHandler` handler when contract requires it. You can disable this feature with `setMountResponseContentTypeHandler`

## Operation model

If you need to access to your operation model while handling the request, you can configure the router factory to push it inside the `RoutingContext` with `setOperationModelKey`:

    options.setOperationModelKey("operationModel");
    routerFactory.setOptions(options);

    // Add an handler that uses the operation model
    routerFactory
      .operation("listPets")
      .handler(
        routingContext -> {
        JsonObject operation = routingContext.get("operationModel");

        routingContext
          .response()
          .setStatusCode(200)
          .setStatusMessage("OK")
          // Write the response with operation id "listPets"
          .end(operation.getString("operationId"));
    });

## Body Handler

Router Factory automatically mounts a `BodyHandler` to manage request bodies. You can configure the instance of `BodyHandler` (e.g. to change upload directory) with `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 `rootHandler`

## Router factory handlers mount order

Handlers are loaded by the router factory in this order:

1. Body handler

2. Custom global handlers

3. Configured `AuthenticationHandler`s

4. Generated `ValidationHandler`

5. User handlers or "Not implemented" handler (if enabled)

## Generate the router

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

    Router router = routerFactory.createRouter();

    HttpServer server = vertx.createHttpServer(new HttpServerOptions().setPort(8080).setHost("localhost"));
    server.requestHandler(router).listen();

This method can fail with a `RouterFactoryException`.