# Vert.x OpenAPI

Vert.x OpenAPI extends Vert.x to support OpenAPI 3 in version 3.0 and 3.1.

Vert.x OpenAPI can:

- parse and validate your OpenAPI contract.

- parse and validate incoming requests according to your OpenAPI contract.

- parse and validate outgoing responses according to your OpenAPI contract.

## 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-openapi</artifactId>
      <version>5.0.2</version>
    </dependency>

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

    dependencies {
      compile 'io.vertx:vertx-openapi:5.0.2'
    }

## `OpenAPIContract`

When using Vert.x OpenAPI you always start with creating an instance of `OpenAPIContract` from your contract.

    String pathToContract = ".../.../myContract.json"; // json or yaml
    Future<OpenAPIContract> contract = OpenAPIContract.from(vertx, pathToContract);

| Due to security reasons this library is not downloading external references from your contract. In case your contract requires external resources, they must be downloaded upfront and also provided to the `OpenAPIContract`.

The example below shows a snippet from an example OpenAPI contract that includes a reference to an external resource and how to create an instance of `OpenAPIContract`.

    paths:
      /pets:
        get:
          operationId: listPets
          parameters:
            - name: query
              schema:
                $ref: 'https://example.com/pet-components#/components/schemas/Query'

    String pathToContract = ".../.../myContract.json"; // json or yaml
    String pathToComponents = ".../.../myComponents.json"; // json or yaml
    Map<String, String> additionalContractFiles = new HashMap<>();
    additionalContractFiles.put("https://example.com/pet-components",
      pathToComponents);

    Future<OpenAPIContract> contract =
      OpenAPIContract.from(vertx, pathToContract, additionalContractFiles);

| During the instantiation of `OpenAPIContract` the contract gets validated. In case your contract does not match the OpenAPI specification or uses features which are not yet supported an error is thrown.

### Path, Operation, Parameter

The `OpenAPIContract` interface offers methods to navigate to the `Path`, `Operation` and `Parameter` objects of the OpenAPI contract.

    OpenAPIContract contract = getContract();

    for (Path path : contract.getPaths()) {
      for (Parameter pathParameter : path.getParameters()) {
        // example methods of a OpenAPI parameter object
        pathParameter.isRequired();
        pathParameter.getSchema();
      }
      for (Operation operation : path.getOperations()) {
        // example methods of a OpenAPI operation object
        operation.getOperationId();
        operation.getRequestBody();
        operation.getParameters();
      }
    }

## Validation

Vert.x OpenAPI checks both whether the content is syntactically correct and whether it corresponds to the schema. If no schema is defined, or the content is binary no schema validation is performed. Currently, only the following media types are supported:

- application/json

- application/json+hal

- application/octet-stream

- multipart/form-data

| It is planned to support more media types in the future. It is also planned to support custom implementations of `ContentAnalyser`, so that any media type can be validated.

### Validation of Requests

The `RequestValidator` offers multiple validate methods to validate incoming requests.

    OpenAPIContract contract = getContract();
    RequestValidator validator = RequestValidator.create(vertx, contract);

    vertx.createHttpServer().requestHandler(httpServerRequest -> {
      // Operation id must be determined for every request which is inefficient
      validator.validate(httpServerRequest).onSuccess(validatedRequest -> {
        validatedRequest.getBody(); // returns the body
        validatedRequest.getHeaders(); // returns the header
        // ..
        // ..
      });

      // Operation id will be passed to save effort for determining
      validator.validate(httpServerRequest, "yourOperationId")
        .onSuccess(validatedRequest -> {
          // do something
        });
    }).listen(0);

The `RequestValidator` also offers a signature of the validate method that consumes a `ValidatableRequest`.

    OpenAPIContract contract = getContract();
    RequestValidator validator = RequestValidator.create(vertx, contract);

    ValidatableRequest request = getValidatableRequest();
    validator.validate(request, "yourOperationId").onSuccess(validatedRequest -> {
      validatedRequest.getBody(); // returns the body
      validatedRequest.getHeaders(); // returns the header
      // ..
      // ..
    });

| The parameters in a `ValidatableRequest` must be stored in a specific format depending on the style, location and if they are exploded or not, otherwise the `RequestValidator` can’t validate the request. The required format MUST exactly look like as described in the JavaDoc of `RequestValidator`.

### Validation of Responses

The `ResponseValidator` offers a validate method to validate responses. `ValidatableResponse` offers multiple create methods to build validatable responses easily.

In case that the validation of a response has passed, the returned `ValidatedResponse` can directly be sent back to the client.

    OpenAPIContract contract = getContract();
    ResponseValidator validator = ResponseValidator.create(vertx, contract);

    JsonObject cat = new JsonObject().put("name", "foo");
    ValidatableResponse response =
      ValidatableResponse.create(200, cat.toBuffer(), APPLICATION_JSON.toString());

    vertx.createHttpServer().requestHandler(httpServerRequest -> {
      validator.validate(response, "yourOperationId")
        .onSuccess(validatedResponse -> {
          validatedResponse.getBody(); // returns the body
          validatedResponse.getHeaders(); // returns the header
          // ..
          // ..
          // send back the validated response
          validatedResponse.send(httpServerRequest.response());
        });
    });

| The parameters in a `ValidatableResponse` must be stored in a specific format depending on the style, location and if they are exploded or not, otherwise the `ResponseValidator` can’t validate the response. The required format MUST exactly look like as described in the JavaDoc of `ResponseValidator`.

### Handle Validation Exceptions

A `ValidatorException` is thrown, if the validation of a request or response fails. The validation can fail for formal reasons, such as the wrong format for a parameter or the absence of a required parameter. However, validation can of course also fail because the content does not match the defined schema. In this case a `SchemaValidationException` is thrown. It is a subclass of ValidatorException and provides access to the related `OutputUnit` to allow further analysis of the error.