Clean Architecture With NodeJS Mongoose and MongoDB

Dominick Caponi
Nov 4 · 3 min read

Not long ago, I published a series of articles going over how to get a Rails app up and running on AWS using Docker. Don’t get me wrong, I love Rails and how it enables me to quickly bootstrap APIs together to validate concepts like my anonymous rating system that I’ve been circling around my workplace to get some honest feedback on my work (shameless plug, go sign up and try it out) and I’ve decided to jump on the NodeJS bandwagon for this post.

I wanted to experiment with a completely different architectural style than the standard MVC configuration that Rails “forces” you to adopt. For this post, we’ll go over how to set up an app that follows Uncle Bob’s Clean Architecture.

https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html

The way it works is quite simple. The center represents things that don’t or shouldn’t change, like models or schemas. Each ring moving out, represents things that change more frequently and depend on the stability of inner layers.

I put up some example code to show what this looks like in practice. I model a school’s administration system. In it, we see two entities, a student and a class. These entities don’t exhibit any behavior and have a specific shape.

The use cases represent business logic like creating a new student but only if that student has a universally unique email, or adding a class but only if it has a unique name and level. Use cases depend on the student or class models looking and behaving a certain way, but a change to the use case will not affect how the entities are implemented.

Then if you’re coming from a MVC world, you’ll see our familiar controllers and presenters. In this style, we inject the use cases to the controllers to do business logic on the entities. The controllers are only responsible for parsing the request, passing the requisite information to the use case, receiving a response from the use case and passing it along to a formatter and then rendering the response assembled by the formatter. This setup decouples the controller implementation from the actual business logic in the use case such that the use case is unaware of which framework we implement.

The outer ring represents things like frameworks and data access implementations. This is where we’ll add a repository or interface for doing queries against the database and the database initialization logic. Since I used Mongoose and plan to share schemas across entities for relationships, I split the Mongoose schemas from the Mongoose model and access implementations. I also split the Mongoose schemas from the entities to keep the rule that the entities themselves should not depend on or be aware of the database implementation. Each entity’s database.js represents the MongoDB collection we’re accessing. This gets injected into a repository which exposes a query interface. I plan to write an abstract repository and standardized the interface such that you can inherit from it and implement specialized logic depending on the database implementation that gets injected.

You’ll notice this repository tries to follow the “screaming architecture” organization, as in, this should look like some kind of “student admin app” rather than a MVC or Express web application.

This should say, Im a Students service, not I’m a MVC Express App

Beyond that, as this is a super simplistic setup for my own (and hopefully your) learning, the only other major parts are the entities being managed. I have a folder for students and one for classes. Inside each folder is a specialized implementation of the routes, controller methods and data access.

I’m still working on improving the structure and implementing relationships like “add student to class” and I therefore welcome any feedback you may have on this! As I said before, I thought this would be a neat way to try rolling my own web app architectural style based on what some really smart people suggest and the only way one can learn is to get more advice from other smart people. Let me know what you think in the comments or drop me a line!