Building SPA with Event Sourcing and CQRS Pattern

Acknowledgement: This is a cross-posting over Building Applications with Event Sourcing and CQRS Pattern at Kloud blog.

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:]

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.

  1. The interface IUserNameScope defines model property and change function. This inherits $scope.
  2. The interface is injected to both link and controller of the directive UserName that implements ng.IDirective.
  3. A link function of the directive takes care of all DOM related ones.
  4. The link function calls the function declared in $scope to send AJAX request to Web API.
  5. A POST AJAX request is sent through userNameFactory to the server.
  6. A response comes from the server as a promise format and the response is passed to replayViewFactory 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 comsumed 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.

  1. Based on the type of the request passed, an appropriate request handler is selected.
  2. The request handler converts the request into a corresponding event. In this code sample, the UsernameChangeRequest is converted to UsernameChangedEvent by the handler.
  3. 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,

  1. A user action is captured at a client-side and passed to a server-side as a request.
  2. The user action request is converted to an event by request handlers.
  3. 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.