Don’t start from Scratch!
At Wolox we are developing a wide variety of projects. As NodeJS grew up and converted into one of the main API development technology, the need of having a Bootstrap was clear. NodeJS is not a standardized technology with strong conventions: there are many libraries with the same behavior, different API structures, routers, loggers, configurations and so on. Working at a software factory with 15+ NodeJS projects and more than 25 developers in this technology which can rotate project at any time, requires a Bootstrap to maintain our organization standard and to fix common issues in our projects easily. So we created our structure and now we are sharing it to you!
Our root includes the following folders:
- App: here, we put all the main development components. We are going deeply in this folder later.
- Config: this folder is used for the environment variables management. We have an index with the names of the variables (usually divided in the database, rollbar, and session secrets) and one file for each environment which can overwrite the default value or add specific env vars just for that environment.
- Docs: here we have our API documents. We use DictumJS for documentation.
- Migrations: this one is for our migrations. We use Sequelize as our ORM, and we have an index to check if the migrations have run. Our policy is to stop the start in development env if migrations didn’t run, and to run them automatically in other environments.
- Scripts: we use these folders to add all the kickoff scripts. They have an entry point and a few scripts which prepare Bootstrap to start a new project.
- Test: the logic to run out tests is here. We use Mocha and Chai as our testing framework.
Our API entry point is the app.JS file where we import and configure Express to. Some configurations are body parser, cors, static documents, port, and rollbar.
We use the MVC pattern in our app folder. Usually, the frontend is developed in ReactJS because of their complexity, so we don’t have views. Our main folders are controllers, models, Middlewares, services, and logger, and their responsibility is:
- Controllers: every exported controller method should receive a request, a response and the next parameters from express. Its responsibility is validating and formatting the request, calling the services, modeling methods and returning the response formatting if it is necessary. Also, handling errors should be done here. The controllers are grouped by resource such as users, albums and so on.
- Logger: we use Winston logger using 2 levels, errors and complete history. We save logs in files with their timestamps.
- Middlewares: here we add our shared logic between controllers, usually auth methods or redirections with headers. Also validating common format requests as query or body params should be here.
- Services: our services are responsible for interacting with external services and database management. Usually we have one file per external service.
- Models: the model should be as simple as possible, just fields and Sequelize configurations. We try to not putting logic here but it is permitted to do an specific model validation as password requirements for an user.
Also we have another important file: the routes files. These are where we define the paths for express using Middlewares and controllers method, and an error handler that set status codes and generic error messages.
Projects can also have a helpers file. A helper should be generic: it must work on any project so here cant’s be any business logic. Usually, there are libraries wrappers such as our Moment wrapper.
Package JSON scripts
The most useful scripts we made with NPM are:
- Console: we run our Node Console which loads models and services. For more information you could read this: Node REPL article.
- Coveralls: run our testing coverage with NYC.
- Lint: we have out lint check and lint fix scripts using Eslint. Our Eslint configuration will be explained in a future post.
- Pre-commit, Pre-start, and Pre-test: run lint check so no commit can be done without passing the linter, testing or starting the app.
- Start-dev: we use Nodemon to start our app in development mode.
- Migrations: command for running the migrations with Sequelize.
After two years using the Bootstrap, we managed to have a very complete version of it. Anyways, we have lots of ideas for new features and improvements.
We want the Bootstrap to select a database that the project needs and kickoff with that configuration. Also, this will check Mongo using Mongoose instead of Sequelize.
We have opened a Pull request for the Factory Girl configuration which created instances of our models for testing purpose.
We want to add a default health check, JSON Schemas, for validating parameters and Swagger for documentation.
Testing Jest and trying ES6 proxies are things we own ourselves and are in our TO DO list.
Last but not least, we want to add scripts for creating and configuring the database, something like create-db and drop-db.
Our Express JS Bootstrap is open source and you can find it here. Feel free to comment about what do you think about our structure, the packages we use, and I would like to know how your NodeJS structure projects are.
Thanks for reading!