This tutorial focuses on the MVC architectural pattern, including its implementation in a project using ExpressJS.
Software architecture is like a blueprint for building software, defining the structure and communication of components.
This is similar to building a physical structure from a prototype. There are different architectural patterns like client-server, peer-to-peer, and MVC.
This tutorial is divided into two parts. The first part covers theoretical concepts and the second part covers a simple project.
The tutorial covers the theoretical concept of the MVC pattern and a simple project based on it.
A brief history of the MVC framework
The origin of this MVC architecture was close to the early development stage of Graphical User Interface (GUI). In the late 1970s, a renowned computer scientist named Trygve Reenskaug first introduced this MVC architecture.
In his design, it has 4 parts – model, view, thing, editor. Later on, in 1987, this architecture has been introduced in the Smalltalk programming language.
Finally, the MVC architectural pattern has been accepted as a general concept for the first time in 1988.
Though this framework has been introduced for quite a long time still, in modern web development it is used because of its simplicity.
Introduction to MVC framework
The MVC stands for Model-View-Controller
is basically an architectural pattern that simply separates a web application into three main logical parts.
The logical parts are Model, View, and Controller. It allows multiple developers to work on the same application simultaneously.
In simple words, the frontend logic, backend logic, and database logic are being implemented under the same umbrella where the View layer is used to represent the presentation part which means UI.
The Model layer is concerned for implementing the backend logic and it has no connection with the View layer.
Finally, the controller layer comes to play an interesting part, it simply makes the connection between model and view.
It is also known as the brain of the application in the MVC architecture because it controls how the data will be displayed.
Let’s see a visual representation of this framework in the below diagram
Here, in the diagram, you can notice that the controller is playing the role of the brain of an application because it is making a connection between the View layer and the Model layer.
We will discuss the Model, View, and Controller separately in the following section.
Model
The Model layer is used to handle all the data logic that the user works with.
The Model component simply represents the data that is being transferred from controller components.
It basically refers to the database, if you are using an SQL database like MySQL then it will be your model component or if you are using a NoSQL database like MongoDB then it will be considered as the model component.
For example, a Student object will retrieve the student information from the database and manipulates the data, updates the data, and sends the data back to the database or render the same data.
View
The layer which is used to present the data in front of the user is known as the View layer. In other words, what users can see is considered as the View components.
View components simply request the model to retrieve information and present the data as output to the user.
View components can be in different forms like charts, boxes, and so on.
It basically focuses on user interactivity and how nicely the data can be presented.
Controller
The Controller layer is the brain of the application that is based on the MVC architectural pattern.
It simply makes a bridge between the View component and the Model component. It makes the application interactive.
When a request comes from the user, it tells the model to change the data based on the request and it also tells the View to present the changed data.
Moreover, if any bad request comes it simply rejects that request.
That means errors are also being handled in this Controller component.
Pros of the MVC framework
Though the MVC architectural pattern is one of the oldest patterns, it is still popular for developing modern web applications.
There are many positive reasons for using this pattern in web applications.
Let’s see a few of them in the below section:
- It can handle and organize large-size web applications
- It Supports Asynchronous Method Invocation and you can write your business logic asynchronously
- It can be modified easily
- The development process is faster
- It supports Test-Driven-Development(TDD)
- Maintenance is easy in this framework
- Search Engine Optimization (SEO) Friendly
- Provides clean separation of concerns(SoC)
Cons of the MVC framework
You can see a lot of advantages of the MVC architectural pattern in the previous section but there are also some disadvantages of using this framework.
The major problem of using this framework is that the View layer is not able to contact the Model layer directly. It needs help from the Controller layer.
Apart from this reason there are a few more and let’s see them in the below section:
- It is very difficult to do the unit test with this framework
- There is no formal validation support
- Increased complexity and Inefficiency of data may occur
- Reading, changing, and reusing the data is difficult in this model
- Expertise needed in multiple fields at the same time
- This may create conflicts while working with multiple developers parallelly
- Difficult to manage a huge number of codes in the controller
This is all about the MVC architectural pattern.
If you have come this far in this tutorial then you have already completed the theoretical portion.
Now, it’s time to implement our theoretical knowledge into the real world, and to do so the best way is to create a project.
In the following section, we will simply create a registration form where users can register themselves with their credentials and we are doing it by following the MVC architectural pattern.
MVC architectural pattern implementation with ExpressJs
We will make a registration form and to do so we will be using ExpressJS a popular framework of NodeJS, Mongoose as the database, and EJS for the server-side-rendering.
Let us assume that, you have already familiar with these concepts and how to create a server and connect the MongoDB database.
We will discuss a little bit about the environment set up in the below section:
Environment Setup
Setting up the environment is the most important part of any application development because without a proper environment you can not implement any functionality.
For the backend, we need to install some important packages. But at first, we will create a folder named mvc-app
, and inside this, we have to give a command in our terminal and the command is
npm init
or
npm init -y
This command will create a package.json
file for us, from where we will be able to manage our installed packages and also control the version of our application.
If you want to create the package manually then you need to give the command npm init
and if you want to create the file as a whole then you need to type npm init -y
After that, we will install our necessary packages like express, mongoose, ejs. Express is a popular NodeJS framework and the mongoose is the Object Data Modeling library for MongoDB.
We will run the NPM
command to install these. See the below example :
npm install express mongoose ejs
or
npm i express mongoose ejs
Here, with the help of this command, we will be able to install both at a single time. After installing these, our package.json file will look like this
{
"name": "mvc-app",
"version": "1.0.0",
"description": "",
"main": "app.js",
"scripts": {
"start": "node app.js",
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"ejs": "^3.1.6",
"express": "^4.17.1",
"mongoose": "^5.13.7",
}
}
Here, we have set the script as “start”: “node app.js”
and you can see those packages with the version. Our environment has been set up successfully and now we are ready to go to the next part.
Create Node Server
To create a Node server with express we need to require the express library first and then we need to define a Port
number and then create a server with the help of the app.listen()
We will write this code in the app.js
which is our apps entry point. file See the below code example:
const express = require('express')
const app = express()
app.use(express.json())
app.use(cors())
const PORT = 8080
app.listen(PORT, () => {
console.log(`Server is running on PORT ${PORT}...`)
})
Here, you can see that we have set the port as 8080
now if we run the command as npm start
we will be able to see the output as Server is running on PORT 8080...
in the console.
Connect MongoDB Database
Like, express we need to require mongoose for counting the database and we also need the connection credentials from the Atlas MongoDB.
Let me assume that, you have already know about these. See the below code example of the connecting database:
const mongoose = require('mongoose')
const DB = 'mongodb+srv://<YOUR USERNAME>:<YOUR PASSWORD>@cluster0.zozv5.mongodb.net/myFirstDatabase?retryWrites=true&w=majority'
mongoose.connect(DB, {
useNewUrlParser: true,
useUnifiedTopology: true,
}).then(() =>{
console.log('Database connected..')
})
Here, we have saved the credentials in a variable named DB
and we are hiding the credentials of username
and password
You may set your own credentials on that variable.
Finally, we have connected the database with the help of mongoose by using mongoose.connect()
We pass the variable there and write some code for avoiding the warnings.
Create user registration Model
After connecting the MongoDB database, it is time to create our database schema model.
That will give the shape of the data and define how the data will be stored in the database.
We will create it into a separate folder and will name it Models
and inside the model folder, we will create a file named UserModel.js
Inside this folder, we will create a simple database schema model.
See the below code example:
const mongoose = require('mongoose')
const userSchema = new mongoose.Schema({
name : {
type : String,
required : true
},
address : {
type : String,
required : true
},
email : {
type : String,
required : true
},
password : {
type : String,
required : true,
}
})
const User = mongoose.model('User',userSchema)
module.exports = User
After creating our database model it is time to create our user controller where we will implement our business logic.
To do so, we will create a separate folder and named the folder as controllers
, and inside this folder, we will create a file named authController.js
it will represent the user registration logic.
See the below code:
const User = require('../models/userModel')
exports.signupGetController = (req,res,next) =>{
res.status(200).render('pages/auth/signup', {
title : 'Register Your Account' ,
error : {},
value : {}
})
}
exports.signupPostController = async (req,res,next) =>{
let {name,address,email,password} = req.body
return res.render('pages/auth/signup',
{
title : 'Register Your Account',
value : {
name,phone,address,nid,email,password
}
})
try{
let user = new User({
name,
address,
email,
password
})
let createdUser = await user.save()
res.redirect('/pages/auth/login', {title : 'Log In to your account'});
return createdUser
}catch(err){
console.log(err)
next(err)
}
}
Here, we simply create two controllers one is for getting the signup page and another one is for the signup the user.
Inside them, we have implemented our business logic and also connect with the View.
Here, we have used our route, and let me assume that you have already aware of creating routes in NodeJS.
It is very simple and easy and as that is not the purpose of our tutorial so we are skipping it. Next, we will implement the View layer.
Create View layer
As we know, the View layer is used for the presentation of data to the user.
In our application, we will create a folder named, views
and inside that folder, we will create a file named signup.ejs
, and here we will implement our frontend code.
To make things simple we are using the bootstrap. See the below code:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-KyZXEAg3QhqLMpG8r+8fhAXLRk2vvoC2f3B09zVXn8CA5QIVfZOJ3BCsw2P0p/We" crossorigin="anonymous">
<link rel="stylesheet" href="/styles/style.css">
<title>
<%= title %>
</title>
</head>
<body>
<div class="container my-container">
<div class="row">
<div class="col-md-6 offset-3">
<div class="card card-body ">
<h4>Register Your Account</h4>
<form action="/auth/signup" method="POST">
<div class="form-group ">
<label for="name">Full Name</label>
<input
type="text"
name="name"
id="name"
class="form-control <%=error.name ? 'is-invalid' : '' %>" value="<%=value.name ? value.name : '' %>">
<div class="invalid-feedback">
<%= error.name && error.name %>
</div>
</div>
<div class="form-group">
<label for="address">Address</label>
<input
type="text"
name="address"
id="address"
class="form-control <%=error.address ? 'is-invalid' : '' %>"
value="<%=value.address ? value.address : '' %>">
<div class="invalid-feedback">
<%= error.address && error.address %>
</div>
</div>
<div class="form-group">
<label for="email">Email</label>
<input
type="email"
name="email"
id="email"
class="form-control <%=error.email ? 'is-invalid' : '' %>" value="<%=value.email ? value.email : '' %>">
<div class="invalid-feedback">
<%= error.email && error.email %>
</div>
</div>
<div class="form-group">
<label for="password">Password</label>
<input
type="password"
name="password"
id="password"
class="form-control <%=error.password ? 'is-invalid' : '' %>" value="<%=value.password ? value.password : '' %>">
<div class="invalid-feedback">
<%= error.password && error.password %>
</div>
</div>
<br>
<div class="mb-3">
<input type="submit" value="signup" class="form-control bg-dark text-white">
</div>
</form>
<p>Registered Already? <a href="/auth/login">login</a></p>
</div>
</div>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js" integrity="sha384-U1DAWAznBHeqEIlVSCgzq+c9gqGAJn5c/t99JyeKa9xxaYpSvHU5awsuZVVFIhvj" crossorigin="anonymous"></script>
</body>
</html>
Here, we have implemented our views layer and by doing that we have completed our MVC pattern.
If you notice, you can see that we have created our Model, we have also created our controller and write business logic and finally, we have created the views layer for presenting the data to the user.
It is time to check the output, and we will be doing that in the next section.
Output
To check the output, we need to give npm start
command in our terminal and if everything goes okay then our app will be running on port number 8080
Now, in the browser, we will hit our specific routes and in our case that is http://localhost:8080/auth/signup
and see what happens:
You can see that the moment we have hit that specific route a nice page has appeared.
That means our Views layer has been working perfectly.
Now, it’s time to input some data and see if our data has been updated in the database or not.
Here, you can see that our data has been updated successfully in our MongoDB database.
Conclusion
In this whole tutorial, we have covered the theoretical concept of the MVC architectural pattern and also create a simple registration project by applying our theoretical concept practically.
In that project, you can see how the controller makes a bridge between the Model and the View components and you may relate your theoretical knowledge by seeing a practical project.
Now, it’s your time to make your hands dirty by creating your own application by following the MVC framework.
But not try to do a large thing as a whole. Instead of doing that, you may try to take small steps.
For example, you may create the login section first and make it work after that, move on to the next small part and then implement it.
This is all about the MVC architectural pattern and the implementation with ExpressJS and if you have faced any issues, feel free to comment here and I will try to solve your problem.