Building a reactive web service with Spring Webflux, Kotlin, and PostgreSQL
This post shows how to create a reactive web service with Spring Webflux, Kotlin, PostgreSQL
For the context,Spring Framework 5 introduced the so-called Reactive Stack. The keyword
reactive
refers to the Reactive Manifesto, which is a specification for asynchronous stream processing with non-blocking back-pressure. This specification is a joint collaboration between engineers from Netflix, Pivotal, Red Hat, Twitter and many others. It has been implemented in many languages such as: Java, Javascript, Swift, NET, etc.
In short, Spring Webflux is a non-blocking web framework that uses Reactor library, which implements the Reactive Streams Specifications, to asynchronously manage HTTP requests.
Requirements
Say we want to build an HTTP service that can do the following:
curl -XPOST /api/users/create -d '{"name": "some-name", "email": "some-email"}'
curl -XPOST /api/users/fetch -d '{"userid": 123}'
curl -XPOST /api/users/all
Note: the final code repo is here
Let’s start the journey by going to Spring Initializr. It is a very handy tool to generate the skeleton project.
- Project: Gradle Project
- Language: Kotlin
- Spring Boot: 2.2.0 (SNAPSHOT)
- Group: com.dvliman
- Artifact: demo
- Dependencies: Reactive Web
- Generate Project — ⌘ + ⏎
At this point, if you run ./gradlew bootRun
, you should see something like this:
Good! Now we just need to add additional dependencies:
Note: At the time of writing, there is no “official” reactive JDBC drivers. JDBC is inherently a blocking API. However, there are some third-party libraries that we can use. I picked David Moten’s rxjava2-jdbc library because it has a great documentation and it implements the Reactive Streams specifications
Design
Before we jump into coding, let’s think about what we need to build. At the minimum, we will need to:
- read a configuration file such as database connection string
- be able to read and write some data into our database
- process HTTP requests
Coding
It is a good idea to start thinking about the data. So let’s define the schema
And write some queries to get a feel for how it works and what not
Next, let’s write a code to read the config file:
The @Value
annotation takes a SPEL-expression to evaluate config values in the application.properties
which contains the database connection string
Okay, now we can add a @Configuration
for all our beans
With database connection bean setup, we can start wiring up the model and repository. So let’s work on that:
Notice how the return type signature is Mono<User>
or Flux<User>
? They are both implementations of Reactive Streams Publisher interface. I am not going to go into too much details about Reactive Streams but in essence:
- Mono is a stream of 0..1 elements
- Flux is a stream of 0..N elements
- a
Publisher<T>
is responsible for publishing elements of typeT
and provides asubscribe
method for subscribers to connect to it - a
Subscriber<T>
connects to aPublisher
, receives a confirmation viaonSubscribe
, then receive data via theonNext
callbacks and additional signals viaonError
andonComplete
- a
Subscription
represents a link between aPublisher
and aSubscriber
, and allows for backpressuring the publisher withrequest
or terminating the link withcancel
- a
Processor
combines the capabilities of aPublisher
and aSubscriber
in a single interface
The next class to take a look is the class that handles the HTTP requests
In Spring Webflux, HTTP handler is essentially a function that takes HTTP request and return HTTP response. (ServerRequest) -> Mono<ServerResponse>
Finally, let’s add a router that routes incoming HTTP requests to the HTTP handler based on URL, HTTP method, and Content-Type header
That is it! Now you can test with curl: