In the previous post, we created a Spring Boot application which offers a Reactive Web API. We’ll cover in this one how to implement the client-side using Angular with EventSource and RxJS’ Observable.
Guide’s Table of Contents
Table of Contents
- Full Reactive Stack – Introduction
- Backend side with Spring Boot, WebFlux and MongoDB
- Frontend Reactive Client with Angular and EventSource (this post)
- Running the application, Comparing WebFlux and MVC, and Conclusions
This part of the guide is focused on the client side of the system. We already created a Reactive Web Endpoint that can supply Server-Sent Events but, how to use it in a more realistic example? I’ll try to cover the answer to that question.
As a disclaimer, I’m far from being an expert in Angular and Typescript so the application has room for improvement. I’ll skip the standard basics of Angular that the client contains and jump almost directly into the Reactive Service. If you want to learn Angular don’t use this post, check a proper tutorial (those are referenced below).
To be honest, I chose Angular (version 4) to implement the frontend side since I have some experience with this framework. In any case, you could use the instructions given here to implement the solution in any other framework since the reactive functionality is mainly supported by RxJS and EventSource (a specification that is part of HTML5).
You may argue that other web frameworks have better support for reactive patterns. But, in any case, bear in mind that the reactive approach in this example focuses on the interface with the server. The rest of the client code is quite simple and doesn’t use publisher/subscriber pattern between web components.
Creating the Angular application
To get the Angular project skeleton you have two alternatives:
- Clone the quickstart project, as detailed on this page.
- Use the
angular-clitool to create the project template, as detailed also in the documentation.
For both alternatives, you need also Node.js (including
npm) installed on your system. The full version of this application has been built using the Angular CLI, so I recommend you to download it as indicated in the linked documentation.
What we’ll build is a simple application that allows us to ask for the available quotes to the server in a reactive manner (using Server-Sent Events) or in a classic blocking style. That distinction will come from the Angular Service we’ll use, so we’ll implement two to showcase the differences. As soon as it receives quotes, the list will get updated.
To make it a little bit more interesting, if we click on a quote the full content will be displayed in a different component on the screen. So, it’s basically a master-detail view with the master rows being loaded dynamically using Reactive patterns.
As you can see in the figure above, our application has three simple Angular components and two services. The component at the top of the hierarchy is the App Component, which acts just as a wrapper for the Quotes Component in our scenario.
The Quotes Component is the core component of our application and it utilizes the Quote Reactive Service and the Quote Blocking Service through Dependency Injection. The Quote Detail Component will be placed on the right side, and it’s just a simple one showing the full contents of the selected Quote object.
The rest of the files in the GitHub repository are tests, styles, dependency management, module definitions, etc. As mentioned before, if you’re not very familiar with Angular JS I recommend you to follow the basic Tour of Heroes tutorial, in which you’ll grasp all these concepts. For this post, let’s focus on how the Quote Reactive Service works and its connection with the Component.
The Angular Reactive service
Let’s have a look at the code of the reactive service that interacts with the backend using Server-Sent Events.
Now, some explanation about the most important ideas in that code:
- With EventSource we connect to the endpoint setting a Content Type
text/event-stream. That way, as we saw in the previous section, we open a channel in which the server will send us events, using the so-called Server-Sent Events mechanism. We connect to the backend from our code by creating the EventSource object, passing the endpoint in which the server exposes this functionality. The code includes a condition to pass the page and size parameters only if you use them in the URL.
- Whenever we receive an event through the EventSource object (
onmessage), we update the Quote array including the new element. However, since EventSource is a very specific object for connecting and receiving data from the server, we don’t use it directly in other parts of our code: we create and handle a ReactiveX (RxJS) Observable object. We apply here this reactive pattern over the Quote array, meaning that any Subscriber to that Observable can receive events when the array gets updated – an action that we perform by calling
- As detailed in the code comments, whenever the stream is closed by the remote, we treat it as normal and we complete the observer.
The Angular Components – Quick Overview
The part interacting with the Services (both blocking and reactive) is the Quotes Component:
This component is using one of the services (via dependency injection) when the user presses a button, depending on the configuration that he chooses. It holds the result inside an
Observable<Quote> object. That’s the most important part of it. Now the
quotes field can be used with an
async pipe from our HTML template (
quotes.component.html) to display them on our page (see below).
As you can see, no matter to which service we’re calling, the result will be an
Observable. The implementation is neutral so we can see the differences between the two approaches in a transparent manner.
In our HTML template, we’ll pass the Observable object so that means there is an implicit subscription mechanism (from the template to the component) that updates our page whenever an event is received from the server. To get that working in Angular we use the
async pipe in our iteration loop:
As per the documentation, the Async pipe subscribes to the Observable and marks the component as changed whenever a new event comes. That’s exactly what we want to do there, hence the
*ngFor using the quotes array has the async pipe.
Running the frontend
No need to say that you should make sure that the backend side is up and running.
We can run our application from the command line (inside the Angular folder) by running
npm run ng serve. Then, if we access to
http://localhost:4200 with our browser, we’ll see this screen:
We have two buttons available to choose between a Reactive or a Blocking request, being that the switch between calling one service or the other. Besides, we can also pick if we want pagination and its corresponding configuration.
Keep in mind that, depending on your machine, you may have problems when requesting all the data at once (no pagination). In that case, you can change the backend code (controller) to limit the number of quotes returned. Check the backend post for more details.
We can now play with all these options and see how the quotes load either at once or one by one depending if we execute a blocking request or a reactive one. Can you spot the differences? Which one gives a better user experience in your opinion? We’ll cover that in the next section/post of this guide.
Continue reading the Guide
Continue reading the post about comparing WebFlux and Blocking web calls, which also details how to run the whole application with Docker.