Node.js applications following an MVC architecture

Good architecture is key to any software development success. This not only ensures easy development processes among teams, but also the scalability of the application. It makes sure that whenever new changes are needed, the developers will not have a hard time refactoring various aspects of the code.

1. MVC Architecture

There are many architecture patterns in different languages like MVT in Python, MVVM in Android, and MVC in JavaScript applications.

MVC architecture divides the whole application into three parts; the Model, the View and the Controller.

1.1. Model

This part defines our data. It is where our schemas and models are located, i.e the blueprint of our application’s data.

1.2. View

This includes templates and any other form of interaction the user has with the application. It is where the data defined by our Model is presented to the user.

1.3. Controller

The business logic is handled in this part. This includes the database reading and writing, and any other modifications that the data undergo. This connects the Model and View.

2. Refactoring to MVC

With that in mind, we can get into our code and start refactoring it to follow the MVC pattern. The base code (prior to alterations) can be found on Github.

In order to transition our application to an MVC pattern, we will need controllers. Note that we already have our models, i.e the model files in the models directory, and our views will be the routes files in the routes folder, as we are not rendering any pages when the user interacts with the API endpoints.

Go ahead and create a directory called controllers in the root level. Then add a file named auth.controller.js which will handle all our auth route’s logic.

mvc-files

Next, add the following exports in the auth.controller.js file. Here we are exporting two functions.

exports.login = (req, res) => {

}

exports.signup = (req, res) => {

}

The login and signup functions will have access to the request and response bodies of our requests, and we will handle the signup and login processes here.

In the controller, import the bcrypt and User model. Then move the entire password hashing functions and mongoose CRUD methods to the respective functions in the controller file.

function-blocks

Import the controller in the routes/auth.js file. This will allow you to access the exported functions. Then, where there were the login and signup implementations, call the controller methods respectively.

const controller = require('../controllers/auth.controller')

router.get('/login', controller.login);

router.post('/signup', controller.signup);

In case you haven’t noticed, we did not move the generateToken method. This is because we can place it in its own file so that you can reuse it in all controllers. So I will create a root-level directory called utils and create a file known as utils.js. And in here is where I will place my generateToken function and any other reusable functions.

const jwt = require('jsonwebtoken')
const tokenSecret = process.env.TOKEN_SECRET

exports.generateToken = (user) => jwt.sign({data: user}, tokenSecret, {expiresIn: '24h'})

Then, in my controller, I will import the utils file to access the exported functions.

controller-utils

And with that, you have some clean MVC architecture. This follows the principle of “separation of concerns” where we decouple our code into very small units which can be handled independently. This is an important aspect to follow, especially in a team, to allow smooth collaboration.

The fully refactored code can be found on Github.

Related posts:

Session Management in Node.js using ExpressJS and Express Session
Next Generation Server Compression With Brotli
Getting Started with Fastify Node.js Framework and Faunadb
Creating A Continuous Integration Test Workflow Using GitHub Actions
How to Connect MongoDB to Node.js Using Mongoose
Node.js versus Next.js - A React Approach
How to Use Modular Patterns in Node.js
Concepts of TCP, Explained with Node.js
Hapi vs Koa vs Express
Getting Started with JIMP image processing
Environment Variables in Node.js
Consuming the Unsplash API using Node.js Graphql API
Building a Websocket Powered Tic-Tac-Toe Game with Adonis.js
A Vanilla Node.js REST API without Frameworks such us Express
Getting Started with Google Sheets API in Node.js
Useful Node.js Tools, Tutorials And Resources
Open-sourced node.js modules at Browserling
Creating a Weather app in Node.js using the Openweathermap API
Getting Started with Node.js Child Processes
Get Started With Node: An Introduction To APIs, HTTP And ES6+ JavaScript
Golang vs. Node.js: Defining the Best Solution
Getting Started with Node.js Event Emitter
How To Build and Test a Node.js REST API with Express on Ubuntu 18.04
Introduction to the Koa.js Framework
How to Perform Custom Ranking for Records from a MongoDB Database in Node.js
Keeping Node.js Fast: Tools, Techniques, And Tips For Making High-Performance Node.js Servers
Implementing Secret Key Cryptography in JavaScript
Implementing AWS S3 Functionalities on a Node.js GraphQL API
Sharing Code Between Projects: Lessons Learned In The Trenches
Why Node.js is Great for Backend Development?
Getting Started with the Quasar Framework
Introduction to Job Scheduling in Node.js