= Vert.x OpenAPI Router
:toc: left

Vert.x OpenAPI Router is based on https://vertx.io/docs/vertx-openapi/java/[Vert.x OpenAPI] and only provides the router functionality.

Vert.x OpenAPI Router can:

* generate a router according to your OpenAPI contract, with correct paths & methods.

== Using Vert.x OpenAPI Router

To use Vert.x OpenAPI Router, 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-router</artifactId>
  <version>5.0.7</version>
</dependency>
----

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

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

== RouterBuilder

With the `link:../../apidocs/io/vertx/ext/web/openapi/router/RouterBuilder.html[RouterBuilder]` you can easily generate a Vert.x Web Router based on the passed
`link:../../apidocs/io/vertx/openapi/contract/OpenAPIContract.html[OpenAPIContract]`.

[source,java]
----
OpenAPIContract contract = getContract();
RouterBuilder routerBuilder = RouterBuilder.create(vertx, contract);
Router router = routerBuilder.createRouter();

// In case that a BodyHandler was applied before, it is necessary to pass a RequestExtractor
RouterBuilder.create(vertx, contract, RequestExtractor.withBodyHandler());
----

The `link:../../apidocs/io/vertx/ext/web/openapi/router/RouterBuilder.html[RouterBuilder]` provides methods to access the generated routes.
These routes can then be customized by adding custom handlers or enable / disable the validation.

[source,java]
----
OpenAPIRoute getPetsRoute = routerBuilder.getRoute("getPets");

// Disables validation for this route.
getPetsRoute.setDoValidation(false);

for (OpenAPIRoute route : routerBuilder.getRoutes()) {
  // Access the operation object from the contract
  Operation operation = route.getOperation();

  // Add a custom handler
  route.addHandler(routingContext -> {
    // do something
  });

  // Add a failure handler
  route.addFailureHandler(routingContext -> {
    // do something
  });
}
----

After a successful validation of the incoming request, the validated parameters and request body are stored in the RoutingContext and can be accessed inside your custom handlers.

[source,java]
----
OpenAPIRoute putPetRoute = routerBuilder.getRoute("putPet");

putPetRoute.addHandler(routingContext -> {
  ValidatedRequest validatedRequest =
    routingContext.get(RouterBuilder.KEY_META_DATA_VALIDATED_REQUEST);

  validatedRequest.getBody(); // returns the body
  validatedRequest.getHeaders(); // returns the header
  // ..
  // ..
});
----

=== Define security handlers

Security is an important aspect of the OpenAPI specification.
The `link:../../apidocs/io/vertx/ext/web/openapi/router/RouterBuilder.html#security-java.lang.String-[security]` allows you to define security handlers.

Users are expected to call this method for each security scheme defined in the OpenAPI contract.
Not doing so will result in a failure when generating the router.
Also providing other handlers that the ones defined in the contract will result in a failure.

A security handler can be automatically configured for the cases of `apiKey` and `http` security schemes.
For other cases, you need to provide a custom handler factory that receives as input the specified configuration from the OpenAPI contract.

For example:

[source,java]
----
RouterBuilder routerBuilder = RouterBuilder.create(vertx, contract);

// Add a security handler for "api_key" security scheme
// configuration will be automatically read from the contract and applied
// to the handler
routerBuilder
  .security("api_key")
  .apiKeyHandler(APIKeyHandler.create(provider));

// Add a security handler for "http" "bearer" security scheme
routerBuilder
  .security("http_bearer")
  .httpHandler(JWTAuthHandler.create(providerJWT));
----

Of course Oauth2/openIdConnect are also supported, given that these modes are more complex to configure, instead of providing a simple configuration object, you need to provide a factory that can creates the handler as you need.
The factory will receive the configuration from the contract, or in case of `openIdConnect` the configuration discovery URL.

[source,java]
----
RouterBuilder routerBuilder = RouterBuilder.create(vertx, contract);

// Add a security handler for "oauth2" security scheme
routerBuilder
  .security("oauth2")
  .oauth2Handler("/callback", flowsConfig -> {
    // flowsConfig is a JsonObject with the configuration for the flows
    // you can use it to create the "providerOAuth2" instance
    return OAuth2AuthHandler.create(
      vertx,
      providerOAuth2,
      // there should a relation between this origin and the callback above
      "https://my-application-server.com/callback");
  });
----

Discovery may sound simpler and if you are working with a openId compliant server you can use the the `openIdConnect` security scheme.

[source,java]
----
RouterBuilder routerBuilder = RouterBuilder.create(vertx, contract);

// Add a security handler for "openIdConnect" security scheme
routerBuilder
  .security("openIdConnect")
  .openIdConnectHandler("/callback", discoveryUrl -> {
    return OpenIDConnectAuth.discover(
      vertx,
      new OAuth2Options()
        .setClientId("client-id")
        .setClientSecret("client-secret"))
      .map(openIdConnect -> {
        return OAuth2AuthHandler.create(
          vertx,
          openIdConnect,
          // there should a relation between this origin and the callback above
          "https://my-application-server.com/callback");
      });
  });
----