Create a simple rest service with Vert.x & Kotlin - Part1
Published On: 2019/04/03
In this article, we will walk through the code to setup a REST WebService project in Vert.x using Kotlin Language. Eclipse Vert.x is a tool-kit for building reactive applications on the JVM. Vert.x is event driven, non blocking and polyglot, which makes it an excellent platform for building microservices. Vert.x Starter is helpfull in generating starter settings. Add the dependencies Vert.x Kotlin coroutines and Web.
Maven Configuration
<properties>
<kotlin.coroutines.version>1.1.1</kotlin.coroutines.version>
<jackson-module-kotlin.version>2.9.8</jackson-module-kotlin.version>
</properties>
<dependency>
<groupId>org.jetbrains.kotlinx</groupId>
<artifactId>kotlinx-coroutines-core</artifactId>
<version>${kotlin.coroutines.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.module</groupId>
<artifactId>jackson-module-kotlin</artifactId>
<version>${jackson-module-kotlin.version}</version>
</dependency>
<dependency>
<groupId>io.vertx</groupId>
<artifactId>vertx-lang-kotlin-coroutines</artifactId>
</dependency>
<dependency>
<groupId>io.vertx</groupId>
<artifactId>vertx-web</artifactId>
</dependency>
<dependency>
<groupId>io.vertx</groupId>
<artifactId>vertx-config</artifactId>
</dependency>
The Coroutine & Vert.x Verticle
Essentially, coroutines are light-weight threads which are launched in a context of a given scope. The coroutine feature in Kotlin simplify the work of asynchronous tasks and make the code more readable. Suspend and resume is the idea behind coroutine but writting it sequentially to avoid the congnitive load.
A verticle is an execution unit of code (a task) that can be deployed by Vert.x. This is something similar to an actor in the actor model frameworks like Akka. There can be multiple verticles coexists in a JVM and these are communicate each other through an even bus.
Vert.x Launcher
In this project we write a Launcher class which create Vert.x instance and deploy a verticle. This class is reading the -conf parameter and creating the corresponding deployment options when deploying verticle specified in the argument list..
Main.kt
package com.asyncstream.cloudmessage.rest
import io.vertx.core.Launcher
fun main() {
Launcher.executeCommand("run", "-conf", "src/main/resources/application-conf.json", "com.asyncstream.cloudmessage.rest.ResourceAPIVerticle")
}
Vert.x CoroutineVerticle for REST Service
CoroutineVerticle is a verticle which run its start and stop methods in coroutine. The ResourceAPIVerticle class in this project extends the CoroutineVerticle of vertx-kotlin-coroutine package.
The start method of this class creates a router which handles the requests landing into this verticle. As the json data mapping is handled by the jackson’s KotlinModule register it to the vert.x core.
override suspend fun start() {
val router = createRouter()
val server = vertx.createHttpServer(httpServerOptionsOf()
.setSsl(true)
.setUseAlpn(true)
.setPemKeyCertOptions(
PemKeyCertOptions().setKeyPath(location.resolve("ca.key").toString())
.setCertPath(
location.resolve("ca.crt").toString())))
Json.mapper.registerModule(KotlinModule())
Json.prettyMapper.registerModule(KotlinModule())
server.requestHandler { router.handle(it) }
.listenAwait(config.getInteger("https.port", 7443))
}
private fun Route.coroutineHandler(fn: suspend (RoutingContext) -> Unit): Route {
return handler { ctx ->
launch(ctx.vertx().dispatcher()) {
try {
fn(ctx)
} catch (e: Exception) {
ctx.fail(e)
}
}
}
}
private suspend fun createRouter() = Router.router(vertx).apply {
// To get the access token.
post("/login").handler(BodyHandler.create()).coroutineHandler { rc ->
val userJson = rc.bodyAsJson
val user = keycloak.authenticateAwait(userJson)
rc.response().end(user.principal().toString())
}
get("/test").produces("application/json").coroutineHandler {
it.response()
.putHeader("content-type", "application/json; charset=utf-8")
.end(Json.encodePrettily("Test"));
}
// Exception handling code goes here.
}
route().handler { ctx ->
ctx.fail(HttpStatusException(HttpResponseStatus.NOT_FOUND.code()))
}
route().failureHandler { failureRoutingContext ->
val statusCode = failureRoutingContext.statusCode()
val failure = failureRoutingContext.failure()
if (statusCode == -1) {
if (failure is HttpStatusException)
response(failureRoutingContext.response(), failure.statusCode, failure.message)
else
response(failureRoutingContext.response(), HttpResponseStatus.INTERNAL_SERVER_ERROR.code(),
failure.message)
} else {
response(failureRoutingContext.response(), statusCode, failure?.message)
}
}
Conclusion
In the part-1 of this article explains the project setup and the code to create a REST service in Vert.x using Kotlin coroutine. The source code of this article is available in the github.