REST API without Java Servlets
Using Vert.x, RxJava and Postgresql
This article is a step by step tutorial which explains how to develop a simple REST API using Vert.x as the HTTP request handler and Postgresql as the database backend. Full source code for this tutorial can be found here if someone wants to directly jump in to the source code.
Following is the simple business user story considered in this API implementation.
As an API consumer, I should be able to create a new vehicle owner in the system by providing following information.
- First name
- Last name
- NIC
- Contact Numbers [Mobile, Office, Home]To create successful vehicle owner resource, First name, Last name, NIC and at-least a single contact number should be sent.
Make sure business logic and domain model is tested
First, we will create a simple domain model to implement the above business rules.
After few TDD iterations VehicleOwner
, ContactNumbers
and Address
domain classes were implemented with the support of VehicleOwnerTest
and ContactNumbersTest
unit test classes. I used JUnit 5 as the unit test framework. Refer my previous article — What I like most in JUnit 5- to get to know more about the reason.
Expose REST API
Now we will focus on the externally exposing part of this application — the REST API. This API is implemented using Vert.x. Vert.x is not a Servlet based HTTP listening framework. Actually, it is an event-driven application framework which runs on JVM. Architecture of Vert.x is similar to Node. I hope following simple digram will give you a head start to understand how Vert.x do the same which Servlet does with HTTP requests.
Let’s start from AdminToolsVerticle
which acts as the triggering point of the application. It extends AbstractVerticle
from core Vert.x library. AdminToolsVerticle's
start() method does few important things:
- Starts a HTTP server to listen to all the HTTP requests.
- Register all the
Routes
need to be exposed from thisVerticle
. - Creates a JDBC Client.
Above I mentioned AdminToolsVerticle
class is the starting point of the application. But, Java runtime does not know about that. We have to instruct Java runtime to run the application from start() method. Instructions need to be given in the build.gradle
as shown below.
Next we will see how Vehicle Owner resource APIs are defined in VehicleOwnerRoute
class. There is nothing complex when it comes to register routes in Vert.x, but if you miss following line in your route, you will waste few minutes debugging the error for requests which contains a body payload.
router.route("/api/resource*").handler(BodyHandler.create());
Integrate with Database
In AdminToolsVerticle
, we initiated Jdbc client. Since we are hoping to use RxJava in service layer classes, Jdbc client should be initialized with RxJava Vert.x instance.
At last, VehicleOwnerService
does the last bits. It saves newly created VehicleOwner object to the database.
For this simple application, we need to create a single table to persist Vehicle Owners. Following is the DDL for creating vehicle_owner
table in Postgres.
Run the Verticle
Finally, we are ready to expose our Vehicle Owner REST API to the consumers. We are few steps behind.
- Build the fat jar file using Shadow Jar Gradle plugin.
./gradlew shadowJar
- Then run the fat jar file.
java -jar build/libs/majan-admintools-api-1.0-SNAPSHOT-fat.jar
- Then use your favourite REST client to send following request to create new Vehicle Owner resource.
POST /api/vehicleowners HTTP/1.1
Host: localhost:8080
Content-Type: application/json
Cache-Control: no-cache
Postman-Token: 3eb1e239-769f-a9d8-8c13-297480fa7c5c{
"firstName": "Kasun",
"lastName":"Dilunika",
"nic":"84544454445",
"contactNumbers" : {
"mobileNumber": "07772323232"
}
}
You will receive 201 HTTP response with no content.