<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>io.vertx.howtos</groupId>
<artifactId>web-and-openapi-howto</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<vertx.version>4.0.0</vertx.version>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>io.vertx</groupId>
<artifactId>vertx-stack-depchain</artifactId>
<version>${vertx.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>io.vertx</groupId>
<artifactId>vertx-core</artifactId>
</dependency>
<dependency>
<groupId>io.vertx</groupId>
<artifactId>vertx-web</artifactId>
</dependency>
<dependency>
<groupId>io.vertx</groupId>
<artifactId>vertx-web-openapi</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.5.0</version>
<configuration>
<mainClass>io.vertx.howtos.openapi.APIVerticle</mainClass>
</configuration>
</plugin>
</plugins>
</build>
</project> Create Vert.x Web Router from an OpenAPI document
This document will show you how to use your OpenAPI document to create a Vert.x Web Router that validates and extract incoming request parameters.
What you will build
You will build a Vert.x application that manages an in-memory list of pets and serves it through the Petstore API https://github.com/OAI/OpenAPI-Specification/blob/master/examples/v3.0/petstore.yaml
What you need
-
A text editor or IDE
-
Java 8 higher
-
Maven
Create a project
Here is the content of the pom.xml file you should be using:
pom.xmlLoad the OpenAPI document
Vert.x Web API Contract provides you RouterBuilder, an object that helps you to build the Vert.x Web Router starting from the OpenAPI specification.
To load the specification into the start method of your Verticle:
RouterBuilder.create(this.vertx, "petstore.yaml")
.onSuccess(routerBuilder -> { (1)
// You can start building the router using routerBuilder
}).onFailure(cause -> { (2)
// Something went wrong during router factory initialization
startPromise.fail(cause);
}); | 1 | If the loading succeeds, you receive a ready to use instance of RouterBuilder, otherwise |
| 2 | you fail the deploy of the verticle |
Write the handlers
Now you can fit your business logic into the Route handlers using operation(operationId).handler().
For listPets:
routerBuilder.operation("listPets").handler(routingContext ->
routingContext
.response() (1)
.setStatusCode(200)
.putHeader(HttpHeaders.CONTENT_TYPE, "application/json") (2)
.end(new JsonArray(getAllPets()).encode()) (3)
); | 1 | Get the response object |
| 2 | Put Content-type: application/json header |
| 3 | Write the response with all pets |
For createPets:
routerBuilder.operation("createPets").handler(routingContext -> {
RequestParameters params = routingContext.get(ValidationHandler.REQUEST_CONTEXT_KEY); (1)
JsonObject pet = params.body().getJsonObject(); (2)
addPet(pet);
routingContext
.response()
.setStatusCode(200)
.end(); (3)
}); | 1 | Get the parsed parameters container |
| 2 | Extract the parsed body |
| 3 | Write the 200 empty response |
For showPetById:
routerBuilder.operation("showPetById").handler(routingContext -> {
RequestParameters params = routingContext.get("parsedParameters"); (1)
Integer id = params.pathParameter("petId").getInteger(); (2)
Optional<JsonObject> pet = getAllPets()
.stream()
.filter(p -> p.getInteger("id").equals(id))
.findFirst(); (3)
if (pet.isPresent())
routingContext
.response()
.setStatusCode(200)
.putHeader(HttpHeaders.CONTENT_TYPE, "application/json")
.end(pet.get().encode()); (4)
else
routingContext.fail(404, new Exception("Pet not found")); (5)
}); | 1 | Get the parsed parameters container |
| 2 | Extract the parsed path parameter |
| 3 | Search the pet |
| 4 | If pet is present, write the pet in the response |
| 5 | If pet is absent, fail the routing context with 404 |
Get the router
Now we can generate the Router and add the "Not Found" and "Bad Request" error handlers:
Router router = routerBuilder.createRouter(); (1)
router.errorHandler(404, routingContext -> { (2)
JsonObject errorObject = new JsonObject() (3)
.put("code", 404)
.put("message",
(routingContext.failure() != null) ?
routingContext.failure().getMessage() :
"Not Found"
);
routingContext
.response()
.setStatusCode(404)
.putHeader(HttpHeaders.CONTENT_TYPE, "application/json")
.end(errorObject.encode()); (4)
});
router.errorHandler(400, routingContext -> {
JsonObject errorObject = new JsonObject()
.put("code", 400)
.put("message",
(routingContext.failure() != null) ?
routingContext.failure().getMessage() :
"Validation Exception"
);
routingContext
.response()
.setStatusCode(400)
.putHeader(HttpHeaders.CONTENT_TYPE, "application/json")
.end(errorObject.encode());
});
server = vertx.createHttpServer(new HttpServerOptions().setPort(8080).setHost("localhost")); (5)
server.requestHandler(router).listen(); (6)
| 1 | Generate the Router from the RouterBuilder |
| 2 | Mount the 404 not found error handler |
| 3 | Create the error json object with exception message, if any |
| 4 | Write the response with the error object |
| 5 | Instantiate a Vert.x HttpServer |
| 6 | Mount the router on the HttpServer instance |
Complete code
You can find the complete source code of APIVerticle on this how-to repo.
Running the application
The APIVerticle already has a main method, so it can be used as-is to:
-
create a
Vertxcontext, then -
deploy
APIVerticle.
You can run the application from:
-
your IDE, by running the
mainmethod from theAPIVerticleclass, or -
with Maven:
mvn compile exec:java
You can test your API using any command-line tool like curl:
$ curl http://localhost:8080/pets
[{"id":1,"name":"Fufi","tag":"ABC"},{"id":2,"name":"Garfield","tag":"ABC"},{"id":3,"name":"Puffa","tag":"ABC"}]
$ curl http://localhost:8080/pets/3
{"id":3,"name":"Puffa","tag":"ABC"}
$ curl http://localhost:8080/pets/5
{"code":404,"message":"Pet not found"}
$ curl -X POST -H "Content-type: application/json" --data '{"id":4,"name":"Alan"}' http://localhost:8080/pets
$ curl -X POST -H "Content-type: application/json" --data '{"id":4}' http://localhost:8080/pets
{"code":400,"message":"$.name: is missing but it is required"}
$ curl http://localhost:8080/pets
[{"id":1,"name":"Fufi","tag":"ABC"},{"id":2,"name":"Garfield","tag":"ABC"},{"id":3,"name":"Puffa","tag":"ABC"},{"id":4,"name":"Alan"}] Summary
This how-to explained to you:
-
How to create your Vert.x Web Router starting from your OpenAPI document
-
How to extract parsed request parameters
-
How to write Json responses
-
How to define router wide error handlers
-
How to start an HTTP Server and mount the generated router