In this blog post I want to point out the topic of the open sourced Reactive Cloud Native Starter example with Java backend Microservices and a Vue.js frontend web application. The gif below shows the example application. The application simply displays Articles and Authors information on a web page. You also see the creation of Articles with cURL commands in a terminal session and the UI is updated automatically.
(the gif is from the Cloud Native Starter project)
That example was mainly developed by Niklas Heidloff. He wrote a lot of very useful blog posts like Development of Reactive Applications with Quarkus related to that topic.
In this blog post I show, what could be useful to know, when you start with this Cloud Native Starter example for reactive programming to create and consume reactive RESTful APIs in an asynchronous way. I will also give a brief overview of the steps to create an article in the example application.
Let’s start with: What could be useful to know?
From my perspective the following two patterns are good starting points, how to be notified about changes in applications using events, channels and subscriptions, when you begin with this reactive programming example.
The blog post of Lionel Nguyen does simplify the differences of these two patterns used for synchron and asynchron implementations. It is good to have this in mind when we move forward.
“In the Observer pattern, the observers are aware of the observable. But, in Pub-Sub pattern, publishers and subscribers don’t need to know each other. They simply communicate with the help of message queues.” Lionel Nguyen
It’s also good to keep in mind what asynchronous means here is a definition for asynchronous on wikipedia.
“A common way for dealing with asynchrony in a programming interface is to provide subroutines (methods, functions) that return to their caller an object, sometimes called a future or promise, that represents the ongoing events. Such an object will then typically come with a synchronizing operation that blocks until the operation is completed. Some programming languages, such as Cilk, have special syntax for expressing an asynchronous procedure call.” Wikipedia
That guides directly to the topic, how to deal with the “future or promise” in Java? In Java we use CompletableFuture for the asynchronous implementation. Take a look in the workshop documentation for more details. When you use CompletableFuture you also should have a basic understanding of Lambda in Java, here you find a blog post about Lambda expressions in Java on geeksforgeeks. With Lambda you can use functions as parameters for methods.
Now the brief overview of the creation of an Article
With that basics, I want to give a brief overview, how an Article is created in that example. But before I do that, I just want to highlight that Quarkus is used for the implementation of the Cloud Native Starter reactive programming example. As you see in the image below, Quarkus is like a one-stop-shop and has all that we need for the reactive programming. In our case we use Vert.x and MicroProfile out of the box in Quarkus.
The following gif shows the creation sequence of an article in the Cloud Native Starter reactive example. Now futures, events, channels and streams are used in the example. You see the clients Web-App and API Client. The Web-App is running in a browser and the API Client in a terminal session. The two Java Microservices Web-API, Articles and the Node Microservice Authors are running in a Kubernetes Cluster. Kafka is used as the event streaming platform and PostgreSQL as the database.
Here is a simplified description of the steps of the Articles creation and the update of the Web-App content.
1. The Articles Microservice is invoked by using cURL to create an Article and Microservice directly returns a CompletableFuture. (CompletionStage)
... public CompletionStage addArticleReactive(@RequestBody( description = "New article", required = true, content = @Content( schema = @Schema(implementation = Article.class))) Article newArticle) { ...
2. The Articles Microservice applies the needed steps in the CompletableFuture inplementation in “.thenApply” to save the data and notify Kafka of the new Article creation.
... return dataAccess.addArticleReactive(article).thenApply(newArticle -> { sendMessageToKafka(newArticle); return newArticle; }); ...
The Microservice creates a new Article in the Postgresql database and registers for an event stream in Kafka using KafkaProducerRecord from Vert.x. The name for that event stream is “new-article-created“. The name “new-article-created” is used later as the event channel/stream name in the Web-API Microservice.
... KafkaProducerRecord String, String record = KafkaProducerRecord.create("new-article-created", articleId); ...
3. The Web-API Microservice is connected to incoming event messages on the channel/stream “new-article-created” from Kafka using MicroProfile and Vert.x. When a message is identified in Web-API Microservice, the service @Broadcast the information to the @Outgoing “stream-new-article” channel. In the code you see the mapping of the annotations.
... @Incoming("new-article-created") @Outgoing("stream-new-article") @Broadcast ...
Here are two useful extracts of the definition for the MicroProfile reactive messaging.
“A method with both an @Incoming and an @Outgoing annotation is a message processor, it consumes messages from a channel, does some transformation to them, and publishes messages to another channel.”
“Remember that Reactive Messaging interactions are assembled from Reactive Streams. A method annotated with @Incoming is a Reactive Streams subscriber and so consumes messages that fit with the message signature and its annotations.”
4. In the Web-Application we use Axios to connect to the event resource using a REST API of the Web-API Microservice, which does the @Broadcast on the channel/stream “stream-new-article” as you have seen before. If an event message occurred, the Articles will be loaded and displayed on the web page. Here you see the event source registration.
... var source = new EventSource(this.$store.state.endpoints.api + "server-sent-events"); let that = this; source.onmessage = function (event) { that.readArticles(); }; ...
I hope this was useful for you and let’s see what’s next?
Greetings,
Thomas
#vuejs, #asynchronous, #completablefuture, #reactive, #quarkus, #microprofile, #java, #events, #streams, #channels
Leave a Reply