Controller-Service Pattern in Node JS

Posted on March 31, 2025
Profile
Gastón Gaitan
March 31, 2025 · 2 months, 2 weeks ago
Controller-Service Pattern in Node JS

Controller-Service Pattern

The Controller-Service Pattern is a software design pattern that helps structure backend applications by separating concerns. It divides responsibilities between controllers (handling HTTP requests) and services (handling business logic).

Endpoint Definition

This API provides endpoints to manage user data. The main endpoints are:

GET /user/:id  --> Retrieves a user by ID
POST /user     --> Creates a new user

The controller handles these requests and delegates logic to the service.

Controller

The controller is responsible for handling HTTP requests and responses.

// userController.js
const UserService = require('./userService');

class UserController {
    async getUser(req, res) {
        const user = await UserService.getUserById(req.params.id);
        res.json(user);
    }

    async createUser(req, res) {
        const newUser = await UserService.createUser(req.body);
        res.status(201).json(newUser);
    }
}
module.exports = new UserController();

Service

The service contains the business logic and interacts with the data layer.

// userService.js
const UserModel = require('./userModel');

class UserService {
    async getUserById(userId) {
        return await UserModel.findById(userId);
    }

    async createUser(userData) {
        return await UserModel.create(userData);
    }
}
module.exports = new UserService();

Model

The model interacts with the database to store and retrieve user data.

// userModel.js
const mongoose = require('mongoose');

const UserSchema = new mongoose.Schema({
    name: String,
    email: String
});

module.exports = mongoose.model('User', UserSchema);

Routes

The routes define API endpoints and map them to the controller functions.

// routes.js
const express = require('express');
const UserController = require('./userController');
const router = express.Router();

router.get('/user/:id', UserController.getUser);
router.post('/user', UserController.createUser);

module.exports = router;

Benefits of applying the pattern

  • Maintainability: Changes only affect a specific class
  • Readability: The code is easier to understand
  • Testability: Easier to test with unit tests
  • Reusability: Classes can be reused in other contexts
  • Fewer errors: Changes have fewer side effects

Diagram of Controller-Service Pattern

Below is a visual representation of how the pattern works:

Controller-Service Pattern Diagram