[Spring Boot] Making a chat application with WebFlux and MongoDB — Part 1
Introduction
In this article, we are going to implement a chat application using Spring WebFlux. By going with the Reactive Stack, we are going to use MongoDB since it offers reactive database capabilities like tailable cursors.
Background
MongoDB Tailable Cursors
Normally when we query from a database, we end up with a finite data stream
because the database driver opens a cursor to provide matching results then close the cursor when the client reads all results.
Maybe this will be understood better if we understand what a database cursor is. A database cursor in simple words can be thought of as “a pointer to the result set” and clients can iterate through a cursor to retrieve results.
But what is tailable cursor
? According to the MongoDB documentation,
“However, for capped collections you may use a Tailable Cursor that remains open after the client exhausts the results in the initial cursor.”
Capped collection means a fixed-size collection based on the max number of records or max size of collection. It works in a way similar to circular buffers, which automatically removes the oldest documents to make room for new documents.
After clients insert new additional documents into a capped collection, the tailable cursor will continue to retrieve documents.
So with tailable cursor, we can get an infinite data stream
over fixed-size collections because cursor remains open to notify us when a new record is inserted into a collection.
Server-Sent Event
Another important concept in this article is Server-Sent Event (SSE). SSE is HTTP based API dedicated to push stream from server to client. Of course Websockets can be used instead but in this article I decided to use SSE. I plan on making the same chat app using Websockets sometime in the future. Let’s see how SSE and Websockets are different at a high level.
However, there might be a question on “How can you implement this using uni-directional push? Clearly, user is typing and sending new messages”. Well, let us look at the flow of this application:
1. The web page we will implement using React will start by getting stored data (old chat messages) through SSE endpoint and render. Server and client stay connected for future data streaming.
2. A user enters and sends new chat messages on the web. These new messages will be sent to the server and they will be saved to DB.
3. As a new message gets saved, such message will be pushed from server to client through the SSE endpoint.
4. Lastly, the web will re-render as it receives pushed data.
Setup
MongoDB
I installed mongodb-community
on my local machine. Let us look at some commands to start MongoDB and to create a capped collection.
Spring Boot
To get started, we need the following dependencies.
Define MongoDB configurations in application.yml
Server Implementation
Data Model
Reactive Repository
Make sure to annotate the query method with @Tailable
. This will enable infinite data stream using tailable cursors explained earlier.
Controller
Two endpoints will be implemented.
getMessages
endpoint reads from the database and provides SSE. Notice how the Content-Type is set totext/event-stream
.setMessage
endpoint saves a new chat message to the database.
Result
At this point, start the app and open a browser and go to localhost:8080/chat/id/{id}
. Use your favorite REST client tool to post some data to /chat
endpoint or use mongo CLI to add new chat messages to the database. As a new message is saved, such message will show up on the browser like below:
It is observed that SSE endpoint will continue to stay alive until the client is exited.
Conclusion
We looked into how to implement the server side of chat application using the Reactive Stack. In the Part 2, we will discover the client side using React.
Full source can be found at:
Reference: