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 '{"user_id": 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:

Netty started on port(s): 8080
Started ApplicationKt in 7.113 seconds (JVM running for 9.353)

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 type T and provides a subscribe method for subscribers to connect to it
  • a Subscriber<T> connects to a Publisher, receives a confirmation via onSubscribe, then receive data via the onNext callbacks and additional signals via onError and onComplete
  • a Subscription represents a link between a Publisher and a Subscriber, and allows for backpressuring the publisher with request or terminating the link with cancel
  • a Processor combines the capabilities of a Publisher and a Subscriberin 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! You can test with curl: