Kotlin and Spring Boot: Hypermedia Driven Web Service
Learn about HATEOAS, build a state machine to model an article review workflow, use Spring-HATEOAS and see how hypermedia clients adapt. By Prashant Barahi.
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Contents
Kotlin and Spring Boot: Hypermedia Driven Web Service
30 mins
- Getting Started
- What Is a State Machine?
- Three Level Review Workflow
- Building the 3LRW State Machine
- Handling Events
- Understanding Hypermedia Responses
- Supporting Hypermedia in Spring Boot
- Media Types
- Building the “Self” Link
- Affordance
- Building the “update” Link
- Building the Tasks Link
- Understanding the Hypermedia Client
- A Non-Hypermedia-Based Client
- Four Level Review Workflow
- Building the 4LRW State Machine
- Where to Go From Here?
In software engineering, much effort goes toward building a loosely coupled system. A loosely coupled system allows you to reduce the effect of changes made in one part of the system on other parts.
You can decouple the frontend application from the server by making the latter send extra information in the response. This information tells the client what actions are possible on a given resource. Clients can then use this information to drive the application from one state to another. This is HATEOAS.
HATEOAS stands for Hypermedia as the Engine of Application State. Although it sounds overwhelming, the idea is rather simple. It’s the way of designing a REST application so the server embeds hypermedia links as metadata in the response. The server crafts these links using the current application state before sending them to the client. The client can then use those hypermedia links to drive the application from the current state to another.
This article and every other one you’ve read on our website went through a review workflow. In this tutorial, you’ll build a hypermedia-based server by modeling a similar review workflow that’s practiced by our tutorial team.
In the process, you’ll:
- Learn the concepts of HATEOAS.
- Build a state machine to model the review workflow.
- Use Spring-HATEOAS to build a hypermedia-powered Spring Boot server.
- Handle change requirements and see how hypermedia-based clients can adapt.
Getting Started
Click Download Materials at the top or bottom of the tutorial to download the starter project. Fire up the IntelliJ IDEA and select Open…. Then, navigate to and open the starter project.
First, make sure you’ve installed JDK 11 or higher. Open Application.kt and run the project.
Or you can also open a Terminal and execute:
./gradlew bootRun
You’ll find the server running on port 8080.
The starter project also contains a React application in the /ui folder. To build and run it, make sure you have Node.js v16.15.1 and npm v8.11.0 (or greater) installed by executing the following commands:
node -v
And:
npm -v
If you don’t have them, go to the official site to download and install them.
Then, build and run the React application by executing this:
cd ui
npm ci
npm run start
You should find it running on port 3000.
Open your browser and go to http://localhost:3000. By default, it makes requests to localhost:8080 (where the Spring Boot server is running), so you’ll see a list of articles like this:
The app isn’t fully usable now, so minimize it.
Now, look at the starter project. It contains the following files:
- ArticleSeedInitializer.kt seeds the empty database with initial data.
-
StateMachineConfigurer.kt provides APIs you use to configure the states and the transitions of a state machine. Then, you supply it to a
StateMachineFactory
. -
ArticleStateMachineBeanConfig.kt is where you configure
ArticleStateMachineFactory
. -
StateMachineFactoryProvider.kt provides methods to retrieve a
StateMachineFactory
bean you’ve configured. - FakeNetworkDelayFilter.kt adds a random delay to every request.
What Is a State Machine?
A state machine is a mathematical model of computation. It has a finite number of states and can be in any one of them at a time.
It starts from an initial state and responds to events by transitioning from its current state to the next if the current state allows it. On reaching the next state, it becomes ready to accept events again.
In this project, you use a state machine to drive the review workflow. Before you dive into the code, you’ll first learn about the business problem you’ll solve.
Three Level Review Workflow
Each article goes through a review process before it gets published. For now, consider there are just three steps. Call it the Three Level Review Workflow (3LRW)!
The author starts the article. They pick a topic from the topic pool and write the article. Once the draft is ready for review, it goes to the technical editor (TE).
Technical editors proofread the article and perform an expert-level review of the content. They can either approve the article and send it to the final pass editor (FPE) or reject the article with feedback if they feel it needs further polish.
Final pass editors stand as the last line of defense. Once they approve the article, they publish it, making it available to readers. After this, any updates to the article are not allowed. However, if the article fails the quality check, the final pass editor can send it back to the author and the process restarts.
The 3LRW state diagram is:
Next, you’ll model this workflow using a state machine.
Building the 3LRW State Machine
The starter project already has an outline of a state machine implemented.
ArticleState
defines all the states a state machine can go through in 3LRW, namely DRAFT
, AUTHOR_SUBMITTED
,TE_APPROVED
and PUBLISHED
.
Similarly, AUTHOR_SUBMIT
, TE_APPROVE
, TE_REJECT
, FPE_APPROVE
and FPE_REJECT
are the events the 3LRW supports. They’re defined in the ArticleEvent
.
Refer to the state diagram to understand how these events and the states relate to each other.
To build a StateMachine
with a 3LRW configuration, you need a StateMachineFactory
. Therefore, you also need to provide a configuration to the StateMachineFactory
to comply with 3LRW. Open ArticleStateMachineBeanConfig.kt and go to providesThreeLevelReviewStateMachineFactory()
:
fun providesThreeLevelReviewStateMachineFactory(): ArticleStateMachineFactory {
// ...
.withTransitions {
// Author
defineTransition(start = DRAFT, trigger = AUTHOR_SUBMIT, end = AUTHOR_SUBMITTED)
// TODO: define other transitions
}
// ...
This is an incomplete implementation of a 3LRW state machine. So replace all the block content with the following snippet:
// Author
defineTransition(start = DRAFT, trigger = AUTHOR_SUBMIT, end = AUTHOR_SUBMITTED)
// TE
defineTransition(start = AUTHOR_SUBMITTED, trigger = TE_APPROVE, end = TE_APPROVED)
defineTransition(start = AUTHOR_SUBMITTED, trigger = TE_REJECT, end = DRAFT)
// FPE
defineTransition(start = TE_APPROVED, trigger = FPE_APPROVE, end = PUBLISHED)
defineTransition(start = TE_APPROVED, trigger = FPE_REJECT, end = DRAFT)
Here, you’ve defined the event (i.e., trigger
) that — when consumed — causes the state machine to transition from the start
state to the end
state.
Notice the return type of this function is an ArticleStateMachineFactory
. This is just an alias for StateMachineFactory<ArticleState, ArticleEvent>
.