= Vert.x-Web API Contract
:toc: left

Vert.x-Web API Contract brings to Vert.x two features to help you to develop you API:

* HTTP Requests validation
* OpenAPI 3 Support with automatic requests validation

== Using Vert.x API Contract

To use Vert.x API Contract, 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-api-contract</artifactId>
  <version>3.5.1</version>
</dependency>
----

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

[source,groovy,subs="+attributes"]
----
dependencies {
  compile 'io.vertx:vertx-web-api-contract:3.5.1'
}
----

== HTTP Requests validation

Vert.x provides a validation framework that will validate requests for you and will put results of validation inside a container.

To define a `link:../../apidocs/io/vertx/ext/web/api/validation/HTTPRequestValidationHandler.html[HTTPRequestValidationHandler]`:

[source,java]
----
HTTPRequestValidationHandler validationHandler = HTTPRequestValidationHandler.create().addQueryParam("parameterName", ParameterType.INT, true).addFormParamWithPattern("formParameterName", "a{4}", true).addPathParam("pathParam", ParameterType.FLOAT);
----

Then you can mount your validation handler:

[source,java]
----
router.route().handler(BodyHandler.create());

router.get("/awesome/:pathParam")
  // Mount validation handler
  .handler(validationHandler)
  //Mount your handler
  .handler((routingContext) -> {
    // Get Request parameters container
    RequestParameters params = routingContext.get("parsedParameters");

    // Get parameters
    Integer parameterName = params.queryParameter("parameterName").getInteger();
    String formParameterName = params.formParameter("formParameterName").getString();
    Float pathParam = params.pathParameter("pathParam").getFloat();
  })

  //Mount your failure handler
  .failureHandler((routingContext) -> {
    Throwable failure = routingContext.failure();
    if (failure instanceof ValidationException) {
      // Something went wrong during validation!
      String validationErrorMessage = failure.getMessage();
    }
  });
----

If validation succeeds, It returns request parameters inside `link:../../apidocs/io/vertx/ext/web/api/RequestParameters.html[RequestParameters]`, otherwise It will throw a `link:../../apidocs/io/vertx/ext/web/api/validation/ValidationException.html[ValidationException]`

=== Types of request parameters
Every parameter has a type validator, a class that describes the expected type of parameter.
A type validator validates the value, casts it in required language type and then loads it inside a `link:../../apidocs/io/vertx/ext/web/api/RequestParameter.html[RequestParameter]` object. There are three ways to describe the type of your parameter:

* There is a set of prebuilt types that you can use: `link:../../apidocs/io/vertx/ext/web/api/validation/ParameterType.html[ParameterType]`
* You can instantiate a custom instance of prebuilt type validators using static methods of `link:../../apidocs/io/vertx/ext/web/api/validation/ParameterTypeValidator.html[ParameterTypeValidator]` and then load it into `link:../../apidocs/io/vertx/ext/web/api/validation/HTTPRequestValidationHandler.html[HTTPRequestValidationHandler]` using functions ending with `WithCustomTypeValidator`
* You can create your own `ParameterTypeValidator` implementing `link:../../apidocs/io/vertx/ext/web/api/validation/ParameterTypeValidator.html[ParameterTypeValidator]` interface

=== Handling parameters
Now you can handle parameter values:

[source,java]
----
RequestParameters params = routingContext.get("parsedParameters");
RequestParameter awesomeParameter = params.queryParameter("awesomeParameter");
if (awesomeParameter != null) {
  if (!awesomeParameter.isEmpty()) {
    // Parameter exists and isn't empty
    // ParameterTypeValidator mapped the parameter in equivalent language object
    Integer awesome = awesomeParameter.getInteger();
  } else {
    // Parameter exists, but it's empty
  }
} else {
  // Parameter doesn't exist (it's not required)
}
----

As you can see, every parameter is mapped in respective language objects. You can also get a json body:

[source,java]
----
RequestParameter body = params.body();
if (body != null) {
  JsonObject jsonBody = body.getJsonObject();
}
----

== OpenAPI 3 support

Vert.x allows you to use your OpenApi 3 specification directly inside your code using the design first approach. Vert.x-Web provides:

* OpenAPI 3 compliant API specification validation with automatic **loading of external Json schemas**
* Automatic request validation
* Automatic mount of security validation handlers
* Automatic 501 response for not implemented operations
* Router factory to provide all these features to users

You can also use the community project https://github.com/pmlopes/slush-vertx[`slush-vertx`] to generate server code from your OpenAPI 3 specification.

=== The router factory
You can create your web service based on OpenAPI3 specification with `link:../../apidocs/io/vertx/ext/web/api/contract/openapi3/OpenAPI3RouterFactory.html[OpenAPI3RouterFactory]`.
This class, as name says, is a router factory based on your OpenAPI 3 specification.
`link:../../apidocs/io/vertx/ext/web/api/contract/openapi3/OpenAPI3RouterFactory.html[OpenAPI3RouterFactory]` is intended to give you a really simple user interface to use OpenAPI 3 support. It includes:

* Async loading of specification and its schema dependencies
* Mount path with operationId or with combination of path and HTTP method
* Automatic request parameters validation
* Automatic convert OpenAPI style paths to Vert.x style paths
* Lazy methods: operations (combination of paths and HTTP methods) are mounted in declaration order inside specification
* Automatic mount of security validation handlers

=== Create a new router factory
To create a new router factory, Use method `link:../../apidocs/io/vertx/ext/web/api/contract/openapi3/OpenAPI3RouterFactory.html#create-io.vertx.core.Vertx-java.lang.String-io.vertx.core.Handler-[OpenAPI3RouterFactory.create]`.
As location It accepts absolute paths, local paths and local or remote URLs (HTTP or file protocol).

For example:

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

You can also construct a router factory from a remote spec:

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

You can also modify the behaviours of the router factory with `link:../../apidocs/io/vertx/ext/web/api/contract/RouterFactoryOptions.html[RouterFactoryOptions]`.
For example you can ask to router factory to mount the validation failure handler but to not mount the not implemented handler as follows:

[source,java]
----
OpenAPI3RouterFactory routerFactory = ar.result();
// Create and mount options to router factory
RouterFactoryOptions options =
  new RouterFactoryOptions()
  .setMountNotImplementedHandler(true)
  .setMountValidationFailureHandler(false);

routerFactory.setOptions(options);
----

=== Mount the handlers
Now load your first path. There are two functions to load the handlers:

* `link:../../apidocs/io/vertx/ext/web/api/contract/RouterFactory.html#addHandler-io.vertx.core.http.HttpMethod-java.lang.String-io.vertx.core.Handler-[addHandler]`
* `link:../../apidocs/io/vertx/ext/web/api/contract/openapi3/OpenAPI3RouterFactory.html#addHandlerByOperationId-java.lang.String-io.vertx.core.Handler-[addHandlerByOperationId]`

And, of course, two functions to load failure handlers

* `link:../../apidocs/io/vertx/ext/web/api/contract/RouterFactory.html#addFailureHandler-io.vertx.core.http.HttpMethod-java.lang.String-io.vertx.core.Handler-[addFailureHandler]`
* `link:../../apidocs/io/vertx/ext/web/api/contract/openapi3/OpenAPI3RouterFactory.html#addFailureHandlerByOperationId-java.lang.String-io.vertx.core.Handler-[addFailureHandlerByOperationId]`

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

.Path in OpenAPI format
IMPORTANT: If you want to use `link:../../apidocs/io/vertx/ext/web/api/contract/RouterFactory.html#addHandler-io.vertx.core.http.HttpMethod-java.lang.String-io.vertx.core.Handler-[addHandler]` or `link:../../apidocs/io/vertx/ext/web/api/contract/RouterFactory.html#addFailureHandler-io.vertx.core.http.HttpMethod-java.lang.String-io.vertx.core.Handler-[addFailureHandler]` pay attention: You can provide a path only in OpenAPI styles (for example path `/hello/:param` doesn't work)

For example:

[source,java]
----
routerFactory.addHandlerByOperationId("awesomeOperation", routingContext -> {
  RequestParameters params = routingContext.get("parsedParameters");
  RequestParameter body = params.body();
  JsonObject jsonBody = body.getJsonObject();
  // Do something with body
});
routerFactory.addFailureHandlerByOperationId("awesomeOperation", routingContext -> {
  // Handle failure
});
----

.Add operations with operationId
IMPORTANT: Usage of combination of path and HTTP method is allowed, but it's better to add operations handlers with operationId, for performance reasons and to avoid paths nomenclature errors

Now you can use parameter values as described above

== Define security handlers
A security handler is defined by a combination of schema name and scope. You can mount only one security handler for a combination.
For example:

[source,java]
----
routerFactory.addSecurityHandler("security_scheme_name", securityHandler);
----

You can of course use included Vert.x security handlers, for example:

[source,java]
----
routerFactory.addSecurityHandler("jwt_auth", JWTAuthHandler.create(jwtAuthProvider));
----

=== Customize the router factory behaviours
The router factory allows you to customize some behaviours during router generation with
`link:../../apidocs/io/vertx/ext/web/api/contract/RouterFactoryOptions.html[RouterFactoryOptions]`. Router factory can:

* Mount a 501 `Not Implemented` handler for operations where you haven't mounted any handler
* Mount a 400 `Bad Request` handler that manages `ValidationException`
* Mount the `link:../../apidocs/io/vertx/ext/web/handler/ResponseContentTypeHandler.html[ResponseContentTypeHandler]` handler when needed

Give a deeper look at `link:../../apidocs/io/vertx/ext/web/api/contract/RouterFactoryOptions.html[RouterFactoryOptions]` documentation

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

[source,java]
----
Router router = routerFactory.getRouter();

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