Tutorial: Reactive Spring Boot Part 1, Building a Kotlin REST Service
Learn how to create a Spring Boot Kotlin REST service!
Join the DZone community and get the full member experience.
Join For FreeLast month, I presented a live demo at SpringOne Platform, showing how to build a Spring Boot application that displays real-time prices, using Spring (obviously), Kotlin, and JavaFX. The live demo was recorded and is available as a 70-minute video, but I thought it might be easier to digest as a series of shorter videos with an accompanying blog post, explaining each of the steps more slowly and in more detail.
This is the first step: creating a reactive Spring Boot service with Kotlin.
You may also like: Fully Reactive: Spring, Kotlin, and JavaFX Playing Together [Links]
This blog post contains a video showing the process step-by-step and a textual walk-through (adapted from the transcript of the video) for those who prefer a written format.
This tutorial is a series of steps during which we will build a full Spring Boot application featuring a Kotlin back-end, a Java client, and a JavaFX user interface.
This first step in the tutorial is to create a Kotlin Spring Boot application, which serves as the back-end of the application. We'll create a REST service that can be connected to in later parts of the tutorial.
Create a Spring Boot Service
Let's create a new project for our Spring Boot service.
- Select New Project, either from the menu of IntelliJ IDEA or from the start screen.
- Select the Spring Initializr option on the left of the New Project window.
- We're using Java 13 as the SDK for this tutorial, although we're not using any of the Java 13 features (you can download JDK 13.0.1 here, then define a new IntelliJ IDEA SDK for it).
- Enter the group name for the project, and we'll use stock-server as the name.
- We can build this project with Maven or Gradle. We're going to create a Maven project that will generate the pom.xml and Maven wrapper files that we need.
- Choose Kotlin as the language. We'll select Java 11 as the Java version as this is the most recent Long Term Support version for Java, but for the purposes of this project, it makes no difference.
- The project name is automatically populated from the artifact name, we don't need to change this.
- Add a useful description of the project.
- We can optionally change the top-level package if we need to.
Next, we select the Spring Boot Starters we need.
- Choose which version of Spring Boot to use. We're going to use 2.2.0 RC1 for this tutorial because later we'll be using features that are only available in the release candidate.
- We can search for and select which Spring Boot starters we want to use. This is a reactive REST service, so select Reactive Web.
- We'll use the defaults for the project name and location.
IntelliJ IDEA will use Spring Initializr to create the project and then import it correctly into the IDE. Enable auto-import on Maven so when we make changes to the pom.xml file, the project dependencies will automatically be refreshed.
The Spring Boot Project
In the project window, we see the structure of the project that has been created, including a Kotlin directory and the standard default Application
class that Spring Boot creates.
package com.mechanitis.demo.stockservice
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.runApplication
@SpringBootApplication
class StockServiceApplication
fun main(args: Array<String>) {
runApplication<StockServiceApplication>(*args)
}
IntelliJ IDEA Ultimate has full support for Spring applications, which includes gutter icons making it easier to identify and navigate between Spring elements like Spring Beans.
If we take a quick look at the generated pom.xml file, we see not only the selected Spring Boot starters and Kotlin dependencies, we can also see the Spring compiler plugin in the kotlin-maven-plugin. This makes it a bit simpler to work with Spring in Kotlin.
Run this basic application using the shortcut Ctrl+Shift+F10 for Windows or Linux (⌃⇧R for macOS) from inside the Application
class file, or double-press Ctrl ("run anything") and type "StockServiceApplication" to run the application. It should start successfully, with Netty running on port 8080. Stop it with Ctrl+F2 (⌘F2).
Create a REST Controller
Now that we know it all works, we can get started on our own functionality.
- Create a class for our REST Controller. We'll put it in the same Kotlin file to keep things simple for now.
- We need to annotate this as a
@RestController
. - (Tip: we can use Live Templates to create code faster. We can type "fun1" and press tab to create a function that takes a single argument).
- Create a function "prices" which takes the symbol of the stock we want to get the prices for. This method will return Flux<StockPrice>, which will be a constant stream of prices.
@RestController
class RestController() {
fun prices(@PathVariable symbol: String): Flux<StockPrice> {
}
}
Create a Data Class for Stock Price
- (Tip: We can get IntelliJ IDEA to create the
StockPrice
class by pressing Alt+Enter on the redStockPrice
symbol and selecting "Create classStockPrice
") - Create a
StockPrice
class inside this same Kotlin file. - This is going to be Kotlin data class. This is a compact way to declare a class with properties, and we simply declare what we want in the Constructor parameters. We want a symbol for the stock, which is a String, a price, which is a Double, and the time associated with that price, using Java 8's java.time.LocalDateTime.
data class StockPrice(val symbol: String,
val price: Double,
val time: LocalDateTime)
Generate and Return Prices
Now we're going to define what the prices method returns. This method is going to create a Flux
, which emits one randomly generated price every second. We can do this with an interval with a Duration
of one second.
fun prices(symbol: String): Flux<StockPrice> {
return Flux.interval(Duration.ofSeconds(1))
}
(Note: This code will not compile yet)
Then, we can create a new StockPrice
for each of these seconds. Note that in Kotlin, we don't need the "new" keyword. The StockPrice
needs the symbol, a price, which for the purposes of this tutorial will be randomly generated, and a time, which will be "now".
fun prices(symbol: String): Flux<StockPrice> {
return Flux
.interval(Duration.ofSeconds(1))
.map { StockPrice(symbol, randomStockPrice(), LocalDateTime.now()) }
}
(Note: This code will not compile yet)
Create this randomStockPrice
function (we can use Alt+Enter to automatically create it). One way to create an arbitrary Double
is using ThreadLocalRandom
and the nextDouble
method. Let's generate a number between zero and one hundred.
private fun randomStockPrice(): Double {
return ThreadLocalRandom.current().nextDouble(100.0)
}
Since we want to be able to access the prices method via an HTTP Get call, we need to add the @GetMapping annotation to it. It needs a path ("/stocks/{symbol}"), and we need to define what the response to this method looks like. We're going to use TEXT_EVENT_STREAM_VALUE to create a server-sent events streaming endpoint. We need to also declare our symbol parameter as a @PathVariable.
The whole RestController
now looks like:
@RestController
class RestController() {
@GetMapping(value = ["/stocks/{symbol}"],
produces = [MediaType.TEXT_EVENT_STREAM_VALUE])
fun prices(@PathVariable symbol: String): Flux<StockPrice> {
return Flux
.interval(Duration.ofSeconds(1))
.map { StockPrice(symbol, randomStockPrice(), LocalDateTime.now()) }
}
private fun randomStockPrice(): Double {
return ThreadLocalRandom.current().nextDouble(100.0)
}
}
Running the Application
Run the application to see it start up correctly. Open up a web browser and navigate to http://localhost:8080/stocks/DEMO, you should see the events tick once a second, and see the stock price represented as a JSON string:
data:{"symbol":"DEMO","price":89.06318870033823,"time":"2019-10-17T17:00:25.506109"}
Summary
We've created a simple Kotlin Spring Boot application that uses Reactive Streams to emit a randomly generated stock price once a second.
@SpringBootApplication
class StockServiceApplication
fun main(args: Array<String>) {
runApplication<StockServiceApplication>(*args)
}
@RestController
class RestController() {
@GetMapping(value = ["/stocks/{symbol}"], produces = [MediaType.TEXT_EVENT_STREAM_VALUE])
fun prices(@PathVariable symbol: String): Flux<StockPrice> {
return Flux.interval(Duration.ofSeconds(1))
.map { StockPrice(symbol, randomStockPrice(), LocalDateTime.now()) }
}
private fun randomStockPrice(): Double {
return ThreadLocalRandom.current().nextDouble(100.0)
}
}
data class StockPrice(val symbol: String, val price: Double, val time: LocalDateTime)
In the rest of the tutorial, we'll show how to connect to this server to retrieve prices, and how to create a chart that shows the price updates in real-time. Stay tuned!
Full code is available on GitHub.
Further Reading
Fully Reactive: Spring, Kotlin, and JavaFX Playing Together [Links]
Published at DZone with permission of Trisha Gee, DZone MVB. See the original article here.
Opinions expressed by DZone contributors are their own.
Trending
-
Getting Started With Istio in AWS EKS for Multicluster Setup
-
Top 10 Engineering KPIs Technical Leaders Should Know
-
Event-Driven Architecture Using Serverless Technologies
-
Integrating AWS With Salesforce Using Terraform
Comments