So far we’ve talked a lot of theory but haven’t done a lot of code. When new people join my team, this is exactly what we do as part of our onboarding. New Grads, interns, or experienced devs need a form of bootcamp to get them up to speed with our standards and methodologies. Experienced devs often find what we do a bit of a shell shock, as they find that the process to which they are used to, well isn’t good enough.
Our example microservice
You can find our example microservice on github https://github.com/geggleto/node-microservice-example It’s a node-js self-contained docker service. Download, and run yarn go to get it up and running.
The first thing we should take a look at is the lib/
directory as it contains a bunch of goodies. We have a list of 4 subdirectories:
aggregates - Most call these “Models”. An aggregate is a model, for the majority of you.
services - These are read-only data operation classes/functions
repositories- These are write-only data operation classes/functions
handlers - These handle the HTTP interactions. It’s named poorly, I might fix that later.
The second think we should look at is the index.js
file.
We have a list of dependencies at the top, some config of express and a giant block of code pertaining something to do with MongoDB. Since our application requires a connection to Mongo, we don’t start the app until we have an open connection which is why our express app is nested inside the connection promise for Mongo.
Inside the Mongo Promise we define a collection for our events, and 2 routes. One to create an account and one to get the account details. We are using a function to return a “express function” in both instances because we need to pass some dependencies, in this case we are using a weird form of injection that I like to call function factory.
Looking at our handlers, they wrap a typical expressjs handler function with a local scope filled with the dependencies that the function needs. This is required for us to split the function into it’s own file, and also allows us to easily unit test this express handler as it gives us direct control over the handler’s dependencies. If this function wasn’t split out it would be impossible to test.
Our first EventSourced thing
Be prepared to jump around a bit in the code; we’re going to look at the CreateAccount
handler. This function requires 3 other Account objects, AccountService
, AccountRepository
, AccountAggregate
.
Let’s start with the AccountService
. The account service provides methods for finding Accounts. Seem’s pretty simple? Yeah. We have 2 methods defined, findByEmail
, findByAccountId
. They both return a collection of documents that match the criteria. For the purposes of this service, they are events. The system actually only has 1 event that it consumes, which is the event that creates the account, but the ground-work we lay here will save us later when we add more events.
Speaking of event’s we can see that we store a document in the AccountRepository
. It’s fairly simple.
Let’s take a look at aggregates. We have a make
, and replay
method. Make is fairly simple it returns an object, replay
well that’s interesting. Replay will iteratively apply each event, thus building an object from a bunch of small events (this is called projecting). Essentially we are rebuilding the state of the object from all of the events (Event Sourcing) through this replay function and using an accumulator (projection).
That’s pretty much it for this. It’s a very simple system. Over the next blog posts we will be slowly adding onto this codebase to make it a lot more interesting. Be sure to subscribe to follow along.