Presentation of the Vert.x-Swagger project

This post is an in­tro­duc­tion to the Vert.x-​Swagger project, and de­scribe how to use the Swagger-Codegen plug­in and the SwaggerRouter class.

Eclipse Vert.x & Swagger

Vert.x and Vert.x Web are very con­ve­nient to write REST API and es­pe­cially the Router which is very use­ful to man­age all re­sources of an API.

But when I start a new API, I usu­ally use the “design-​first” ap­proach and Swag­ger is my best friend to de­fine what my API is sup­posed to do. And then, comes the “bor­ing” part of the job : con­vert the swag­ger file con­tent into java code. That’s al­ways the same : re­sources, op­er­a­tions, mod­els…

For­tu­nately, Swag­ger pro­vides a code­gen tool : Swagger-​Codegen. With this tool, you can gen­er­ate a server stub based on your swag­ger de­f­i­n­i­tion file. How­ever, even if this gen­er­a­tor pro­vides many dif­fer­ent lan­guages and frame­work, Vert.X is miss­ing.

This is where the Vert.x-​Swagger project comes in.

The project

Vert.x-​Swagger is a maven project pro­vid­ing 2 mod­ules.

vertx-swagger-codegen

It’s a Swagger-​Codegen plug­in, which add the ca­pa­bil­ity of gen­er­at­ing a Java Vert.x Web­Server to the gen­er­a­tor.

The gen­er­ated server mainly con­tains :

  • POJOs for definitions
  • one Ver­ti­cle per tag
  • one Main­Ver­ti­cle, which man­age oth­ers APIVer­ti­cle and start an HttpServer.

The Main­Ver­ti­cle use vertx-​swagger-router

vertx-swagger-router

The main class of this mod­ule is SwaggerRouter. It’s more or less a Fac­tory (and maybe I should re­name the class) that can cre­ate a Router, using the swag­ger de­f­i­n­i­tion file to con­fig­ure all the routes. For each route, it ex­tracts pa­ra­me­ters from the re­quest (Query, Path, Header, Body, Form) and send them on the event­Bus, using ei­ther the operationId as the ad­dress or a com­puted id (just a pa­ra­me­ter in the con­struc­tor).

Let see how it works

For this post, I will use a sim­pli­fied swag­ger file but you can find a more com­plex ex­am­ple here based on the pet­store swag­ger file

Generating the server

First, choose your swag­ger de­f­i­n­i­tion. Here’s a YAML File, but it could be a JSON file:

...waiting for Gist...

Then, down­load these li­braries :

Fi­nally, run this com­mand

java -cp /path/to/swagger-codegen-cli-2.2.2.jar:/path/to/vertx-swagger-codegen-1.0.0.jar io.swagger.codegen.SwaggerCodegen generate \
  -l java-vertx \
  -o path/to/destination/folder \
  -i path/to/swagger/definition \
  --group-id your.group.id \
  --artifact-id your.artifact.id

For more In­for­ma­tion about how Swag­ger­Code­gen works, you can read this https://github.com/swagger-​api/swagger-​codegen#getting-​started

You should have some­thing like that in your con­sole:

[main] INFO io.swagger.parser.Swagger20Parser - reading from ./wineCellarSwagger.yaml
[main] INFO io.swagger.codegen.AbstractGenerator - writing file [path/to/destination/folder]/src/main/java/io/swagger/server/api/model/Bottle.java
[main] INFO io.swagger.codegen.AbstractGenerator - writing file [path/to/destination/folder]/src/main/java/io/swagger/server/api/model/CellarInformation.java
[main] INFO io.swagger.codegen.AbstractGenerator - writing file [path/to/destination/folder]/src/main/java/io/swagger/server/api/verticle/BottlesApi.java
[main] INFO io.swagger.codegen.AbstractGenerator - writing file [path/to/destination/folder]/src/main/java/io/swagger/server/api/verticle/BottlesApiVerticle.java
[main] INFO io.swagger.codegen.AbstractGenerator - writing file [path/to/destination/folder]/src/main/java/io/swagger/server/api/verticle/InformationApi.java
[main] INFO io.swagger.codegen.AbstractGenerator - writing file [path/to/destination/folder]/src/main/java/io/swagger/server/api/verticle/InformationApiVerticle.java
[main] INFO io.swagger.codegen.AbstractGenerator - writing file [path/to/destination/folder]/src/main/resources/swagger.json
[main] INFO io.swagger.codegen.AbstractGenerator - writing file [path/to/destination/folder]/src/main/java/io/swagger/server/api/MainApiVerticle.java
[main] INFO io.swagger.codegen.AbstractGenerator - writing file [path/to/destination/folder]/src/main/resources/vertx-default-jul-logging.properties
[main] INFO io.swagger.codegen.AbstractGenerator - writing file [path/to/destination/folder]/pom.xml
[main] INFO io.swagger.codegen.AbstractGenerator - writing file [path/to/destination/folder]/README.md
[main] INFO io.swagger.codegen.AbstractGenerator - writing file [path/to/destination/folder]/.swagger-codegen-ignore

And this in your des­ti­na­tion folder:

Generated sources

What have been created ?

As you can see in 1, the vertx-​swagger-codegen plug­in has cre­ated one POJO by definition in the swag­ger file.

Example : the bottle definition

...waiting for Gist...

In 2a and 2b you can find :

  • an in­ter­face which con­tains a func­tion per operation
  • a ver­ti­cle which de­fines all operationId and cre­ate Event­Bus con­sumers

Example : the Bottles interface

...waiting for Gist...

Example : the Bottles verticle

...waiting for Gist...

… and now ?

Line 23 of BottlesApiVerticle.java, you can see this

BottlesApi service = new BottlesApiImpl();

This line will not com­pile until the BottlesApiImpl class is cre­ated.

In all XXXAPIVer­ti­cles, you will find a vari­able called ser­vice. It is a XXXAPI type and it is in­stan­ci­ated with a XXXAPIImpl con­truc­tor. This class does not exist yet since it is the busi­ness of your API.

And so you will have to cre­ate these im­ple­men­ta­tions.

Fine, but what if I don’t want to build my API like this ?

Well, Vert.x is un­opin­ion­ated but the way the vertx-​swagger-codegen cre­ates the server stub is not. So if you want to im­ple­ment your API the way you want, while en­joy­ing dy­namic rout­ing based on a swag­ger file, the vertx-​swagger-router li­brary can be used stand­alone.

Just im­port this jar into your project:

...waiting for Gist...

You will be able to cre­ate your Router like this:

FileSystem vertxFileSystem = vertx.fileSystem();
vertxFileSystem.readFile("***YOUR_SWAGGER_FILE***", readFile -> {
    if (readFile.succeeded()) {
        Swagger swagger = new SwaggerParser().parse(readFile.result().toString(Charset.forName("utf-8"))); 
        Router swaggerRouter = SwaggerRouter.swaggerRouter(Router.router(vertx), swagger, vertx.eventBus(), new OperationIdServiceIdResolver());
        [...]
   } else {
        [...]
   }
});

You can ig­nore the last pa­ra­me­ter in SwaggerRouter.swaggerRouter(...). As a re­sult, ad­dresses will be com­puted in­stead of using operationId from the swag­ger file. For in­stance, GET /bottles/{bottle_id} will be­come GET_bot­tles_bottle-​id

Conclusion

Vert.x and Swag­ger are great tools to build and doc­u­ment an API but using both in the same project can be painful. The Vert.x-​Swagger project was made to save time, let­ting the de­vel­op­ers fo­cus­ing on busi­ness code. It can be seen as an API frame­work over Vert.X.

You can also use the SwaggerRouter in your own project with­out using Swagger-​Codegen.

In fu­ture re­leases, more in­for­ma­tion from the swag­ger file will be used to con­fig­ure the router and cer­tainly oth­ers lan­guages will be sup­ported.

Though Vert.x is poly­glot, Vert.x-​Swagger project only sup­ports Java. If you want to con­tribute to sup­port more lan­guages, you’re wel­come :)

Thanks for read­ing.

Next post

Preview of a guide for Java developers

We are introducing the book “A gentle guide to asynchronous programming with Eclipse Vert.x for enterprise application developers”.

Read more
Previous post

Time scheduling with Chime

Eclipse Vert.x executes periodic and delayed actions with periodic and one-shot timers. Chime is a time scheduler verticle that works on the Vert.x event bus.

Read more
Related posts

My first Vert.x 3 Application

Let's say, you heard someone saying that Vert.x is awesome. Ok great, but you may want to try it by yourself. Well, the next natural question is “where do I start ?”

Read more

TCP Client using Eclipse Vert.x, Kotlin and Gradle build

In this blog post, I demonstrate how to write a very simple TCP client that keeps a connection open to a custom-written server in cloud.

Read more

Using the asynchronous SQL client

Finally, back... This post is the fifth post of the introduction to vert.x blog series, after a not-that-small break. In this post we are going to see how we can use JDBC in a vert.x application.

Read more