Building an MVC Pattern Web Application using Node.js, Express.js, and Sequelize

The MVC (Model-View-Controller) pattern is a software design pattern that involves separating an application into three main components: Model, View, and Controller. When implementing the MVC pattern using Node.js and Express.js, you can have a folder structure similar to the following.

What is a Model?

Handles data and data processing. Manages tasks such as data validation, storage, retrieval, and more.

What is a View?

Manages content visible to users. Plays a role in providing data to clients.

What is a Controller?

Acts as an intermediary between the Model and View. Handles client requests, processes corresponding Model operations, and communicates the results to the View.


Example of MVC Pattern Folder Structure

  • Name
    Example of Folder Structure
    Type
    Description

    app.js serves as the entry point for the Express application, managing settings such as routing and middleware. Within the routes folder, routing for each entity (users, posts, etc.) is divided and managed separately.

    Based on this structure, you can implement the MVC pattern by utilizing Express.js middleware and routing to process client requests, and harmonizing data between the Model and View.

Folder Structure

root/
├─ models/
│  ├─ user.js
│  └─ post.js

├─ views/
│  ├─ home.ejs
│  └─ profile.ejs

├─ controllers/
│  ├─ userController.js
│  └─ postController.js

├─ public/ (정적 파일)

├─ routes/
│  ├─ index.js
│  ├─ userRoutes.js
│  └─ postRoutes.js

├─ app.js
└─ package.json

app.js (Express Configuration)

  • Name
    Express Configuration
    Type
    Description

    This involves building a web application using the Express framework and processing web requests primarily through routing. Routing is the mechanism of calling appropriate handler functions based on client requests.

    Comparing it with previous settings, you can see the addition of app.use('/users', userRoutes).

    View Basic Configuration Code

app.js

const express = require('express');
const app = express();
const userRoutes = require('./routes/userRoutes');
const postRoutes = require('./routes/postRoutes');

app.use(express.json());
app.use('/users', userRoutes);
app.use('/posts', postRoutes);

app.listen(3000, () => {
    console.log('Server is running on port 3000');
});

Routes

  • Name
    Defining API Endpoints
    Type
    Description

    This demonstrates defining API endpoints related to users in the routing file, and illustrates how to handle two types of HTTP requests through the user controller.

userRoutes.js

const express = require('express');
const router = express.Router();
const userController = require('../controllers/userController');

router.get('/', userController.getAllUsers);
router.post('/', userController.createUser);

module.exports = router;

Controllers

  • Name
    Handling User Requests
    Type
    Description

    This is the controller that handles user-related logic. The code demonstrates how to process API requests through two examples.

userController.js

const { User } = require('../models');

exports.getAllUsers = async (req, res) => {
    try {
        const users = await User.findAll();
        res.json(users);
    } catch (error) {
        res.status(500).json({ message: 'Error retrieving users' });
    }
};

exports.createUser = async (req, res) => {
const { name, email } = req.body;
    try {
        const newUser = await User.create({ name, email });
        res.json(newUser);
    } catch (error) {
        res.status(500).json({ message: 'Error creating user' });
    }
};

Models

  • Name
    ORM (Defining Models using Sequelize)
    Type
    Description

    This is an example file that uses Sequelize to define database models. Sequelize is a promise-based ORM (Object-Relational Mapping) library for interacting with SQL databases in Node.js.

user.js

const { DataTypes } = require('sequelize');
const sequelize = require('../database');

const User = sequelize.define('User', {
    name: {
        type: DataTypes.STRING,
        allowNull: false
    },
    email: {
        type: DataTypes.STRING,
        allowNull: false
    }
});

module.exports = User;

Summary of the MVC Pattern

Here is a simple sample code. Defining database models using Sequelize requires specific configurations, and when configuring routing and controllers using Express.js, additional considerations such as error handling and security based on file paths and settings are necessary.

While the current article summarizes the MVC pattern, we recommend the MVCS (Service) pattern. Adding a service layer allows for better organization of controller code and modularization of reusable business logic. Separating logic enhances the MVC pattern, enabling a more modular design.