Express.js Routing & Controllers - Structuring Scalable MVC Web Applications

In production backend applications containing dozens or hundreds of endpoints, defining all routes inside a single server.js file leads to unmaintainable spaghetti code. Professional developers separate routing logic into dedicated Router files and encapsulate business operations inside Controller classes following the MVC (Model-View-Controller) architecture.

Structuring a Professional Express Project

my-api/
├── controllers/
│   └── studentController.js   // Business logic & response handling
├── routes/
│   └── studentRoutes.js       // URL route endpoints definition
├── models/
│   └── studentModel.js        // Database schema
├── middleware/
│   └── authMiddleware.js      // JWT / API key verification
└── server.js                  // App initialization & mounting

1. Defining the Controller: studentController.js

// controllers/studentController.js

// Simulated in-memory database
let students = [
  { id: 1, name: 'Amit Kumar', rollNo: 'BCA-101', course: 'Computer Science' },
  { id: 2, name: 'Priya Sharma', rollNo: 'BCA-102', course: 'Information Technology' }
];

// GET /api/students - List all students
exports.getAllStudents = (req, res) => {
  res.status(200).json({
    success: true,
    count: students.length,
    data: students
  });
};

// GET /api/students/:id - Get single student by ID
exports.getStudentById = (req, res) => {
  const studentId = parseInt(req.params.id);
  const student = students.find(s => s.id === studentId);

  if (!student) {
    return res.status(404).json({ success: false, error: 'Student not found' });
  }

  res.status(200).json({ success: true, data: student });
};

// POST /api/students - Create new student
exports.createStudent = (req, res) => {
  const { name, rollNo, course } = req.body;

  if (!name || !rollNo) {
    return res.status(400).json({ success: false, error: 'Name and RollNo are required' });
  }

  const newStudent = { id: students.length + 1, name, rollNo, course: course || 'BCA' };
  students.push(newStudent);

  res.status(201).json({ success: true, data: newStudent });
};

2. Defining the Router: studentRoutes.js

// routes/studentRoutes.js
const express = require('express');
const router = express.Router();
const studentController = require('../controllers/studentController');

// Route Chaining using router.route()
router
  .route('/')
  .get(studentController.getAllStudents)
  .post(studentController.createStudent);

router
  .route('/:id')
  .get(studentController.getStudentById);

module.exports = router;

3. Mounting the Router in server.js

// server.js
const express = require('express');
const studentRoutes = require('./routes/studentRoutes');

const app = express();
app.use(express.json());

// Mount router under the /api/students path prefix
app.use('/api/students', studentRoutes);

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

Frequently Asked Questions (FAQ) - Student & Interview Review

Q1. What is express.Router() and why is it used?

express.Router() creates an isolated instance of middleware and routes (often described as a 'mini-app'). It allows you to organize route handlers into separate modular files (e.g. routes/userRoutes.js, routes/productRoutes.js) instead of placing all endpoints into a single massive server.js file.

Q2. What is the difference between Route Parameters and Query Parameters?

Route parameters (e.g. '/users/:id') identify a specific resource in the path and are accessed via 'req.params.id'. Query parameters (e.g. '/users?role=student&page=1') filter, sort, or paginate results and are accessed via 'req.query.role'.

Q3. What is the MVC (Model-View-Controller) pattern in Node.js?

MVC is a software design pattern that separates concerns: 1) Model represents the database schema and business logic, 2) View is the presentation layer (JSON or HTML), and 3) Controller acts as the intermediary that receives client requests, calls models, and sends responses.

Explore Related Node.js Tutorials & Next Steps

Boost your server-side JavaScript proficiency by studying these closely connected core modules:

Express Middleware Deep Dive

Chain route-level middleware for authorization.

Building Production REST APIs

Implement full CRUD routes in controller files.

Express.js Intro

Review basic app.get and app.post setups.

Share Share on Facebook Share on Twitter Share on LinkedIn Pin on Pinterest Share on Stumbleupon Share on Tumblr Share on Reddit Share on Diggit

You may also like this!