Standards

Vert.x OpenAPI

Preview

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>4.5.11</version>
</dependency>
  • Gradle (in your build.gradle file):

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

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 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.