Event Sourcing and CQRS with Axon!
By: Ben Calus
Tags: Software Development, Axon Framework, Cqrs, Event Sourcing

A framework that does the heavy lifting for us

Luckily for us, there are frameworks that help us to design exactly this kind of applications. In this series, we will have a look at two of them: Lagom and Axon.

The Axon framework, created by AxonIQ, is mainly focused on building applications that leverage techniques like Event Sourcing, CQRS and Event driven architecture. Also a lot of concepts from Domain Driven Design are 1 to 1 mapped to concepts in Axon.

Let’s get acquainted with them in the context of a real world example: a food ordering application.

Photo by Breakslow on Unsplash

The food ordering application

Axon has a very good example of a food ordering application. The application is written in Java and showcases the principles of Event Sourcing and CQRS.

The application is about ordering food, obviously, one of the key developments of the modern world! The application allows a user to create a shopping cart, add items to and remove items from the cart and afterwards checkout the order. Simple enough, right?

Let’s jump in by having a look at the application structure using the Axon framework to see Event Sourcing and CQRS in action. Note that we will implement the example application in a plain Scala project to show all the mechanics of an Axon application.

Conceptual model of the Food Ordering application

1 | Commands, Events and Queries

As usual, we start by defining the core API of the internal application: the commands, events and queries.

Commands will reflect the intent that users can express to change something in the state of the application, like selecting a product to put into their cart.

Commands

A command clearly shows the intent of what a user tries to change in the application. Each of the commands requires at least an identifier that will be used to identify the specific aggregate we want to target. The aggregate can be seen as a single state container. In our case this would be a single shopping cart for a given user and is identified by the foodCartId .

These commands will get processed and converted to events (we’ll see how that works in the command handling section). These are the factual changes to the application’s state and can be modeled as follows:

Events

Events will get stored in an event store. At that point, the events make up for the factual changes within the system and will form a history. As a reaction to this new fact of life, the application will change the in-memory state in accordance with the event to recreate the actual end state at this point in time.

A last essential piece of our API is a way to get the information out. If a user wants to get information about his specific cart for example, a query can be issued.

Queries

Next up, filling the carts with food in the implementation of this API.

2 | Command processing in the write model

Commands are received and translated to events to be stored in the event store. The aggregate is the processor that handles all commands for a specific entity in the system, which is identified by the aggregate identifier. In our case, the cart!

First of all, we define the specifics to this container of state:

Aggregate creation

The Axon framework is able to route the commands to the correct container using the TargetAggregateIdentifier field in the command. This is mapped to the correct aggregate, where the identifier is tagged with AggregateIdentifier .

Additionally, we define how this aggregate needs to handle a command. For example, in case of a SelectProductCommand :

Command handling

The aggregate receives the command and publishes the ProductSelectedEvent to the Axon life cycle. At this point the heavy lifting starts for Axon. It will make sure the event is stored in the event store in Axon server. As soon as the event is stored, we are sure the state cannot be lost anymore.

It’s time to apply the event to our in-memory state of the cart. In Axon, we do this by defining an EventSourcingHandler :

Event handling

We update the selectedProducts variable in the aggregate to include the newly selected products.

Cool, our write side model is fully up to date and we are ready to receive more events. But what about reading this data now? That’s where the read model comes in.

3 | Query side in the read model

The aggregate models a single Cart entity and makes sure the state is up to date to evaluate new incoming commands.

Following the principles of CQRS, we will split query side to a totally separate module. The glue between the two are the events or stateful facts to the application.

We will define a projector that tracks all events and builds a read model:

Read side projector

The foodCartViewRepository represents a specific persistence model that is designed to answer queries from the user. The repository can save the results to a separate database to make sure the latest state is immediately available to be served as a response to issued queries to the application.

This can be done by defining a query handler in the Projector that does exactly that:

Query handling

Time to put it all together!

Photo by Kelly Sikkema on Unsplash

4 | Putting it all together

The application is now capable of receiving commands and answering queries, while the events underneath model the state of the application. But this is all internal to the application and a user of the application should not care. A last important step is to expose the functionality of the application to the outer world.

Let’s create an HTTP controller that is able to expose the application over REST. Any framework could be used to expose the application, so we’ll use the lightweight Akka-HTTP framework here:

Food Ordering Service

For convenience, we only show the endpoints to add some products to the cart and to query the content of the cart.

The bridge between the REST controller and the Axon framework is the commandGateway and queryGateway . These are the hooks to the Axon framework to allow us to issue a command in the application or query some information about our carts. And that’s about it!

Make sure to checkout the full source code on Github.