When we start building an application on cloud, like Azure, we should consider many factors. Those factors include flexibility, scalability, performance and so on. In order to satisfy those factors, components making up the application should be loosely coupled and ready for extension and change at any time. For those considerations, Microsoft has introduced 24 cloud design patterns. Even though they are called as “Cloud Design Patterns”, they can be used just for application development anyway. In this post, I’m going to introduce Event Sourcing Pattern and CQRS Pattern and how they can be used in a single page application (SPA) like AngularJS application.
The complete code sample can be found here.
I’m not going into too much details here to explain what Event Sourcing (ES) Pattern and CQRS Pattern are. According to articles linked above, both ES and CQRS easily get along with each other. As the name itself says, CQRS separates commands from query – commands and query use different dataset and ES supports event stream for data store (commands), and materialisation and replaying (query). Let’s take a look at the diagram below.
[Image from: https://msdn.microsoft.com/en-us/library/dn589792.aspx]
This explains how ES and CQRS work together. Any individual input (or behaviour) from a user on the presentation layer (possibly Angular app in this post) is captured as an event and stored into event stream with timestamp. This storing action is
append-only, ie events are only to be added. Therefore, the event stream becomes a
source of truth, so all events captured and stored into the event stream can be replayed for query or materialised for transaction.
OK. Theory is enough. Let’s build an Angular app with Web API.
Client-side Implementation for Event Triggering
There are three user input fields –
Submit button. Each field and button acts as an event. In this code sample, they are named as
UserCreatedEvent. Those events are handled by event handlers at the Web API side. What the Angular app does is to capture the input values when they are being changed and clicked. This is a sample TypeScript code bits for the name field directive.
This HTML is a template used for the directive below.
ng-model will capture the field value and the value will be sent to the server to store event stream.
Please bear in mind that, as this is written in TypeScript, the coding style is slightly different from the original Angular 1.x way.
- The interface
changefunction. This inherits
- The interface is injected to both
controllerof the directive
linkfunction of the directive takes care of all DOM related ones.
linkfunction calls the function declared in
$scopeto send AJAX request to Web API.
- A POST AJAX request is sent through
userNameFactoryto the server.
- A response comes from the server as a
promiseformat and the response is passed to
Name field. Now, let’s have a look how the replay view section looks like.
This HTML template is used for the directive below. The following directive is only to replay responses.
As you can see, this directive only calls the
replayViewFactory.getReplayedView() function to display what changes are. How do those events get consumed at the server-side then? Let’s move onto the next look.
Server-side Implementation for Event Processing
The POST request has been sent through a designated endpoint like:
This request is captured in this Web API action:
The action in the controller merely calls the
this._service.ChangeUsernameAsync(request) method. Not too excited. Let’s dig into the service layer then.
- Based on the type of the request passed, an appropriate request handler is selected.
- The request handler converts the request into a corresponding event. In this code sample, the
UsernameChangeRequestis converted to
UsernameChangedEventby the handler.
- An event processor takes the event and process it.
A question may arise here. How does request handler selection work? Each request handler implements
IRequestHandler and it defines two methods:
Therefore, you can create as many request handlers as you like, and register them into your IoC container (using Autofac for example) like:
In the sample code used here registers five request handlers. If your business logic is way far complex and require many request handlers, you might need to consider moduling those request handlers automatic registration. I’ll discuss this in another post soon. Another question may arise again. How does the event processor work? Let’s have a look. Here’s the event processor:
This is quite similar to the
EventStreamService.ChangeUsernameAsync(). First of all, find all event handlers that can handle the event. Then those selected event handlers process the event as all event handlers implements
To wrap up,
- A user action is captured at a client-side and passed to a server-side as a request.
- The user action request is converted to an event by request handlers.
- The event is then processed and stored into event stream by event handlers.
Of course, I’m not arguing this is the perfect example for event processing. However, at least, it’s working and open for extension, which is good.
Now, all events are raised and stored into event stream with timestamp. Event stream becomes a
source of truth. Therefore, if we want to populate a user’s data against a particular time period, as long as we provide timestamp, we’re able to load the data without impacting on the actual data store. If you run the code sample on your local and make some user input change, you’ll actually be able to see the replayed view.
Now, let’s store the user data into the real data store by event materialisation.
When you hit the
Submit button, the server-side replays all events from the event stream with the current timestamp for materialisation. Then the materialised view is stored into the
User table. As this is considered as another event, another event,
UserCreatedEvent is created and processed by
UserCreatedEventHandler. Unlike other event handlers, it does not only use the event stream repository, but also use the user repository.
In other words, the event itself is stored into the event stream and a user data from the event is stored into the user repository. Once stored, you will be able to find on the screen.
Please note that, if you change
Submit button, you’ll find some difference like the following screen:
So far, we’ve briefly discussed both ES pattern and CQRS pattern with a simple Angular – Web API app. How did you find it? Wouldn’t it be nice for your next application development? Make sure one thing. Applying those patterns might bring overly complex architecture into your application as there are many abstraction layers involved. If your application is relatively simple or small, you don’t have to consider those patterns. However, your application is growing and becomes heavier and complex, then it’s time to consider getting those patterns implemented for your application. Need help? We are Kloudie, the expert group.