Skip to content

Latest commit

 

History

History

event-sourcing-esdb-aggregates

Twitter Follow Github Sponsors blog blog

Github Actions

Event Sourcing with Spring Boot and EventStoreDB using Aggregate pattern

Sample is showing basic Event Sourcing flow. It uses EventStoreDB for event storage and Spring Data JPA backed with PostgreSQL for read models.

The presented use case is Shopping Cart flow:

  1. The customer may add a product to the shopping cart only after opening it.
  2. When selecting and adding a product to the basket customer needs to provide the quantity chosen. The product price is calculated by the system based on the current price list.
  3. The customer may remove a product with a given price from the cart.
  4. The customer can confirm the shopping cart and start the order fulfilment process.
  5. The customer may also cancel the shopping cart and reject all selected products.
  6. After shopping cart confirmation or cancellation, the product can no longer be added or removed from the cart.

Technically it's modelled as Web API written in Spring Boot and Java 22.

Watch the video

Practical introduction to Event Sourcing with Spring Boot and EventStoreDB

Practical introduction to Event Sourcing with Spring Boot and EventStoreDB

Main assumptions

  • explain basics of Event Sourcing, both from the write model (EventStoreDB) and read model part (PostgreSQL and Spring Data JPA),
  • present that you can join classical approach with Event Sourcing without making a massive revolution,
  • CQRS architecture sliced by business features, keeping code that changes together at the same place. Read more in How to slice the codebase effectively?,
  • clean, composable (pure) functions for command, events, projections, query handling, minimising the need for marker interfaces. Thanks to that testability and easier maintenance.
  • easy to use and self-explanatory fluent API for registering commands and projections with possible fallbacks,
  • registering everything into regular DI containers to integrate with other application services.
  • pushing the type/signature enforcement on edge, so when plugging to DI.

Overview

It uses:

  • Aggregate pattern for modelling the business logic,
  • Stores events from the command handler result EventStoreDB,
  • Builds read models using Subscription to $all.
  • Read models are stored to Postgres relational tables with Spring Data JPA.
  • App has Swagger and predefined docker-compose to run and play with samples.

Write Model

  • Sample ShoppingCart aggregate and events represent the business workflow. All events are stored in the same file using sealed classes to be able to understand flow without jumping from one file to another. It also enables better typing support in pattern matching. ShoppingCart also contains when method method defining how to apply events to get the entity state. It uses the Java 22 switch syntax for pattern matching.
  • business logic is encapsulated into aggregate methods. It helps to keep the invariants and business logic in the same place. They are pure functions that take command and/or state and create new events based on the business logic. See sample Adding Product Item to ShoppingCart. This example also shows that you can inject external services to handlers if needed.
  • Code uses functional interfaces in many places to introduce composability and lously coupled, testable code.
  • Added EventStoreDB aggregate store to load entity state and store event created by business logic.
  • Command and query handling logic are grouped/wrapped into application service, to have the single entry point with all possible operations, see ShoppingCartService. It does not keep the additional command/query types definition as they're redundant because of the param types validation.
  • All command handling has to support optimistic concurrency. Implemented full flow using If-Match header and returning ETag. Read more details in my article How to use ETag header for optimistic concurrency

Read Model

Testing

Prerequisites

  1. Install git - https://git-scm.com/downloads.
  2. Install Java JDK 22 (or later) - https://www.oracle.com/java/technologies/downloads/.
  3. Install IntelliJ, Eclipse, VSCode or other preferred IDE.
  4. Install docker - https://docs.docker.com/engine/install/.
  5. Open project folder.

Running

  1. Run: docker-compose up.
  2. Wait until all dockers got are downloaded and running.
  3. You should automatically get:
  4. Open, build and run ECommerceApplication.