1. MVC / Layered Architecture in expressjs

medium · Express.js — Web APIs & middleware

The MVC (Model-View-Controller) pattern is the architectural backbone of scalable applications. In modern Express APIs, we often extend this into a Layered Architecture by adding a Service Layer to separate the "how" from the "what" . 1. The Core Theory: Separation of Concerns Theory: The primary goal of MVC is to ensure that no single file has too much responsibility . Model: The "Source of Truth." It represents your data and the rules for interacting with the database . Controller: The "Coordinator." It receives requests, validates basic input, and decides which service to call . Service Layer (The "Brain"): This is where Business Logic lives . If you need to calculate a discount or check if a user is eligible for a job, that logic goes here—not in the controller . 2. Breaking Down the Layers Layer 1: The Route (The Entrance) Theory: The route is simply a map that connects a URL to a specific controller function . // routes/userRoutes.js const express = require('express'); const router = express.Router(); const userController = require('../controllers/userController'); router.get('/', userController.getAllUsers); // Pure mapping Layer 2: The Controller (The Manager) Theory: The controller should be "thin." Its only job is to extract data from the req , call a service, and send back a res . Mistake: Putting await User.find() here makes your code hard to test and reuse . // controllers/userController.js const userService = require('../services/userService'); exports.getAllUsers = async (req, res, next) => {   try {     const users = await userService.fetchAllUsers(); // Delegation     res.status(200).json(users);   } catch (err) {     next(err); // Pass to Error Middleware   } }; Layer 3: The Service (The Specialist) Theory: Services contain the actual "work" . Because services don't know about req or res , they can be easily tested in isolation or reused in different parts of the app (like a background cron job) . // services/userService.js const User = require('../models/userModel'); exports.fetchAllUsers = async () => {   // Business Logic: e.g., Filter out banned users before returning   return await User.find({ isBanned: false });  }; Layer 4: The Model (The Data) Theory: This layer defines the schema and handles the heavy lifting of database communication (e.g., using Mongoose) . // models/userModel.js const mongoose = require('mongoose'); const userSchema = new mongoose.Schema({   name: { type: String, required: true },   email: { type: String, unique: true } }); module.exports = mongoose.model('User', userSchema); 3. The Execution Flow: A Request's Journey Step-by-Step Process: Client: Sends a GET /api/users request . Route: Identifies the URL and triggers userController.getAllUsers . Controller: Extracts any queries (like ?limit=10 ) and calls userService.fetchAllUsers() . Service: Performs logic (filtering/sorting) and asks the Model for data . Model: Queries the Database and returns the raw data to the Service . Service: Returns the processed data back to the Controller . Controller: Sends the final Response (JSON) back to the Client .

Back to Express.js — Web APIs & middleware

Browse all study material on Careeroza