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.
Patterns Overview
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 – Title
, Name
and Email
– and the Submit
button. Each field and button acts as an event. In this code sample, they are named as SalutationChangedEvent
, UsernameChangedEvent
, EmailChangedEvent
and 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
IUserNameScope
definesmodel
property andchange
function. This inherits$scope
. - The interface is injected to both
link
andcontroller
of the directiveUserName
that implementsng.IDirective
. - A
link
function of the directive takes care of all DOM related ones. - The
link
function calls the function declared in$scope
to send AJAX request to Web API. - A POST AJAX request is sent through
userNameFactory
to the server. - A response comes from the server as a
promise
format and the response is passed toreplayViewFactory
for replay.
Both Title
and Email
fields work the same way as the 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
UsernameChangeRequest
is converted toUsernameChangedEvent
by 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 IEventHandler
interface:
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.
Replaying Events
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.
Materialising Events
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 Title
, Name
, or Email
but not yet click the 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.
Very informative post. What is the diagram software you used to create the diagrams in this post?
Hi, Shalin. Thanks for your comment. The diagram used in this post actually comes from MSDN, https://msdn.microsoft.com/en-us/library/dn589792.aspx. I put the reference URL just underneath the diagram, in case anyone being interested. If you are mentioning other screenshots, I use Snagit (commercial) or PicPick (free for personal use). Hope this helps.
Hi,
why do you not use properties (get/set) on your angular controller to manage events ?
You can use get/set properties to handle events on the Angular side. However, please bear in mind that this post mainly spots on event sourcing pattern. 🙂