NOTE: This is the final part of a five-part series in which I detail how a real-world ASP.NET Web API app using the Command-Query Responsibility Segregation and Event Sourcing (CQRS/ES) patterns and the Redis database might look. Here's Part 1 of this series. The corresponding repository is over on GitHub.
All our work in the previous parts of this series (learning what Command-Query Responsibility Segregation and Event Sourcing are, building the Write Model to modify our aggregate roots, building the Read Model to query data, and building both our Write and Read APIs) has lead to this. We can now test these two APIs using [Postman] and see how they operate.
In this post, the final part of our Real-World CQRS/ES with ASP.NET and Redis series, we will:
- Run the Commands API with both valid and invalid commands.
- Run the Queries API with existent and non-existent data.
- Discuss some shortcomings of this design.
You're on the last lap, so don't stop now!
Command - Creating Locations
The first thing we should do is run a few commands to load our Write and Read models with data. To do that, we're going to use my favorite tool Postman to create some requests.
First, let's run a command to create a new location. Here's a screenshot of the Postman request:
Running this request returns 200 OK, which is what we expect. But what happens if we try to run the exact same request again?
Hey, lookie there! Our validation layer is working!
Let's create another location:
Well, seems our create location process is working fine. Or, at least, it looks like it is.
Query - Locations (All and By ID)
To be sure that our system is properly updating the read model, let's submit a query to our Queries API that returns all locations:
Which looks good. Let's also query for a single location by its ID. First, let's get Location #2:
Now we can query for Location #3:
Oh, wait, that's right, there is no Location #3. So we get back HTTP 400 Bad Request, which is also what we expect. (You could also make this return HTTP 404 Not Found, which is more semantically correct).
OK, great, adding and querying Locations works. But what about Employees?
Command - Creating Employees
Let's first create a new employee and assign him to Location #1:
Let's also create a couple more employees:
So now we should have two employees at Location #1 and a third employee at Location #2. Let's query for employees by location to confirm this.
Query - Employees by Location
Here's our Postman screenshot for the Employees by Location query for each location.
Just as we thought, there are two employees at Location #1 and a third at Location #2.
We're doing pretty darn good so far! But what happens if Reggie Martinez (Employee #3) needs to transfer to Location #2? We can do that with the proper commands.
Command - Assign Employee to Location
Here's a command to move Mr. Martinez to Location #2:
And now, if we query for all employees at Location #2:
I'd say we've done pretty darn good! All our commands do what we expect them to do, and all our queries return the appropriate data. We've now got ourselves a working CQRS/ES project with ASP.NET and Redis!
Shortcomings of This Design
Even though we've done a lot of work on this project and I think we've mostly gotten it right, there's still a few places that I think could be improved:
- All Redis access through repositories. I don't like having the Event Handlers access the Redis database directly, I'd rather have them do that through the repositories. This would be easy to do, I just didn't have time before my publish date.
- Better splitting of requests/commands and commands/events. I don't like how commands always seem to result in exactly one event.
That said, I'm really proud of the way this project turned out. If you see any additional areas for improvement, please let me know in the comments!
In this final part of our Real-World CQRS/ES with ASP.NET and Redis series:
- Ran several queries and commands.
- Confirmed that those queries and commands worked as expected.
- Discussed a couple of shortcomings of this design.
As always, I welcome (civil) comments and discussion on my blog, and feel free to fork or patch or do whatever to the GitHub repository that goes along with this series. Thanks for reading!