Understanding MVC architecture and Router concepts using Express.JS
Table of contents
Model View Controller
Model View Controller is a software design pattern commonly used for developing UI.
It tells us how to organzie various different pieces of code based on their functionalities.
Model -> View -> USER -> Controller
These controllers in Express are the functions that react tot the incoming requests and sned the response accordingly.
The Model is the data. It could be a database or an in-memory information. Model also contains some function to access the database.
View is how the data is presented back to the user, it can be graphs, diagrams, entire web applications.
MVC is meant to simplify our code and make it easier to understand.
Splitting our code into these layers allows our code to be easier to read, update and improve as each layer is responsible for a single thing.
MVC in Express
We will start with our route handlers, these functions process the request coming in and response going out are going to be our controllers.
Start by making a folder named containers. We will create a single controller module for each of our collections of data. So one for friends and one for messages for now.
This breaking down things allow us to work easily when working on large servers.
Make a new module in containers folder named messages.controller.js . This lets us know this fils is for messages and a controller. Create another file friends.controller.js .
Move our handlers to controllers and make them as named functions so it will be easy to debug.
We need to export our friends array to a separate file named friends.models.js as models are where we store our data in MVC architecture.
After doing all this our index.js file will be much cleaner and all our handlers will be in different files making the code more organized.
index.js
const express = require('express');
const friendsController = require('./controllers/friends.controller')
const messagesController = require('./controllers/messages.controller')
const app = express();
const PORT = 3000;
app.use((req, res,next) => {
const start = Date.now();
next();
const delta = Date.now() - start; // calculate time elapsed
console.log(`${req.method} ${req.url} ${delta}ms`);
})
app.use(express.json());
app.listen(PORT, () => {
console.log('Server is listening at PORT', PORT)
})
app.post('/friends', friendsController.postFriends)
app.get('/friends', friendsController.getFriends)
app.get('/friends/:friendID', friendsController.getFriend)
app.get('/', (req, res) => {
res.send('Hello');
})
app.get('/messages', messagesController.getMessages)
app.post('/messages', messagesController.postMessage)
friends.controller.js
const {friends} = require('../models/friends.models')
function getFriends(req, res){
res.json(friends)
}
function postFriends(req, res){
if(!req.body.name){
return res.status(400).json({
error: 'Missing friend name'
})
}
const newFriend = {
name: req.body.name,
id:friends.length
}
friends.push(newFriend);
res.json(newFriend)
}
function getFriend(req, res) {
const friendID = req.params.friendID - 0;
const friend = friends[friendID];
if(friend){
res.status(200).json(friend);
}else {
res.status(404).json({
error: 'friend doesnot exist'
})
}
}
module.exports = {
getFriends,
postFriends,
getFriend,
}
friends.models.js
const friends = [
{name:'Siddhant',
id: 0},
{name:'Amit',
id:1
}];
module.exports = {friends}
This is a simple example of MVC architecture.
Routers
Router is used to organize the routes in our application in smaller groups.
It is like a mini application, it contains it's own set of middlewares and routes just like Express. We use router to break down our application and make it more modular.
Create a Router
const friendsRouter = express.Router()
We can now add our friends route to router instead of adding to our app object directly. We use Router like any other middleware application in Express.
So just like any other middleware we need to use the middleware
app.use(friendsRouter)
We sometimes call this mounting over the app object. Router allows us to mount a group of paths under a specific path.
So, all are friends are going to be in '/friends' path or with something after '/friends/:id' we can mount our friendsRouter on our '/friends' path
app.use('/friends', friendRouter)
After doing this we will change the .post and .get methods.Since our friendsRouter will take everything related to '/friends' path so we can change the post with a '/' and get methods like this
friendsRouter.post('', friendsController.postFriends)
friendsRouter.get('', friendsController.getFriends)
friendsRouter.get('/:friendID', friendsController.getFriend)
Always call the app.use() so express maps requests to all paths starting with '/friends' are routed
Now this can become big chunks of code, so we move our routes to separate folder.
We will make routes folder with two files, friends.router.js and messages.router.js
friends.router.js
const express = require('express');
const friendsController = require('../controllers/friends.controller')
const friendsRouter = express.Router();
friendsRouter.post('', friendsController.postFriends)
friendsRouter.get('', friendsController.getFriends)
friendsRouter.get('/:friendID', friendsController.getFriend)
module.exports = {
friendsRouter
}
We can export our friendsRouter now and work on the methods in the index.js and it will still work
import the friends.router module in index and run the index file.
Do the same for messages.router file
const express = require('express');
const messagesController = require('../controllers/messages.controller');
const messagesRouter = express.Router();
messagesRouter.get('/', messagesController.getMessages);
messagesRouter.post('/', messagesController.postMessage)
module.exports = {
messagesRouter
}
Now we have modules that tell us the functionalities of different routers and we can add middlewares in these specific router files as well that will be specifiv to particular router.
Like we do the following in friends.router file
friendsRouter.use((req,res, next) => {
console.log(req.ip);
next();
})
We are logging ip address using req.ip
function.
Remember to call the next() function in your middleware
On making the request using Postman we will see IP address as '::1' . It is another way of saying localhost. This is IP address 6 syntax.
127.0.0.1 is IP address 4 syntax .
There is something you will notice. The routes that are being logged in our console are that which are passing to our router and not the full path. This is not useful for us. We need to modify our middleware to req.baseURL
Go to the index.js file and update the console
console.log(`${req.method} ${req.baseUrl}${req.url} ${delta}ms`);
We used the req.baseUrl
here.