Simplify Node.js Route Handlers With Middleware A How-To Guide
What I’d like to point out in this post is pretty common issue I had to deal with over and over again and share some patterns that have worked well on small to large sized projects for me. Some time ago I came across a route handler that was 2k lines of code long. Some changes had to be made but each time I tried to understand the control flow, 2–3 mouse scrolls down I was feeling lost. Below is just a hint (not an actual project code):
It might not look so scary from the example above, but trust me, it’s just a fraction of whole handler logic. In such case it becomes very difficult to write unit tests as it would require mocking insane amount of resources. So how to approach this? I broke it into small chunks and assembled back together in form of middleware. I added some level of security in form of e2e test coverage so I was good to go knowing that crucial parts should work as expected and it couldn’t get worse than it is. I started from extracting request body checks into separate middleware as it felt that this is important initial step which is needed to continue serving the request:
Now this middleware does one thing and does it well. It’s easy to reason about and write unit tests for. In case of failed check I pass error to next middleware callback. This step assumes that server is set to capture and handle errors:
Now that I’m sure all body parameters are present and valid I can continue to next step of getting account:
It can’t get much simpler than this, right? It’s safe to refer to req.body.account_id
in getAccount middleware since I took care of validations in our previous middleware. I've assigned account
to res.locals
. This is a recommended way of sharing data between middleware in express apps.
Let’s see how it fits inside the handler:
Handler is now shorter, it’s easier to understand what’s happening and the remainder of logic can be split in similar manner. Important to note here that order of middleware matters as it’s executed sequentially and getAccount middleware depends on valid body parameters to be in place.
My folder structure usually looks like this:
This was just a basic example to share some thoughts and maybe help someone make better decisions when organising their projects.
Learn, explore and share.