Skip to content

2.1 Introduction

Middleware are functions that have access to the request (req), response (res), and a special next function in the request-response cycle. Middleware are functions that run before the request reaches the final route handler.

They can:

  • Run any code
  • Modify req or res
  • End the request-response cycle
  • Call next() to pass control to the next middleware

1. Basics of Middleware

1.1 πŸ”§ Basic Syntax

function middleware(req, res, next) {
// Do something...
next(); // Pass to next middleware or route handler
}

Used like:

app.use(middleware);

πŸ§ͺ Example: Logger Middleware

app.use((req, res, next) => {
console.log(`${req.method} ${req.url}`);
next(); // Continue to next middleware or route
});

1.2 πŸ›  Common Built-in Middleware

MiddlewarePurpose
express.json()Parses JSON bodies in requests
express.urlencoded()Parses URL-encoded form data
express.static()Serves static files like HTML, CSS, JS

1.3 🧭 Where Middleware Runs

Middleware can be:

  1. Application-level – applies to all routes
  2. Route-level – applies only to specific routes
  3. Error-handling – catches and handles errors
  4. Built-in or third-party – like cors, body-parser, morgan

1.4 🧡 Example Flow

app.use(express.json()); // 1: parse JSON
app.use(myLogger); // 2: log request
app.post('/data', (req, res) => {
res.send('Data received');
});

2. Middleware Execution Order

The order in which middleware runs in Express.js is very important, as it follows a top-to-bottom sequence. The order is determined by the way middleware is registered in your application.

  1. Global Middleware

    • Middleware registered with app.use() or specific routes will run in the order they are defined in your code.
  2. Route-Specific Middleware

    • Middleware attached to specific routes (like app.get(), app.post(), etc.) runs in the order it is defined for that route.
  3. Error Handling Middleware

    • Middleware that handles errors is called only if an error is passed to next(err) within another middleware or route handler. These middleware functions must have 4 arguments: (err, req, res, next).

Key Points:

  • 1. Order of Definition Matters: Middleware is executed in the order it is defined.

    • If you define middleware app.use() earlier, it runs before middleware defined later.
  • 2. Call next() to move forward: After each middleware runs, it needs to call next() to pass the request to the next middleware or route handler.

  • 3. If next() is not called, the request is β€œstuck” and will not reach the next middleware or route handler.

2.1 Order with Global Middleware

const express = require('express');
const app = express();
// First middleware
app.use((req, res, next) => {
console.log('First middleware');
next(); // Pass to next middleware
});
// Second middleware
app.use((req, res, next) => {
console.log('Second middleware');
next(); // Pass to next middleware
});
// Route handler
app.get('/', (req, res) => {
res.send('Hello World');
});
// Error handling middleware
app.use((err, req, res, next) => {
console.error('Error:', err);
res.status(500).send('Something went wrong!');
});
app.listen(3000, () => {
console.log('Server running on port 3000');
});

What Happens?

  1. First Middleware β†’ Logs: First middleware
  2. Second Middleware β†’ Logs: Second middleware
  3. Route Handler (GET /) β†’ Sends: Hello World
  4. Error Handling Middleware (if there’s an error) β†’ Catches any errors and responds with a 500 status.

2.2 Order with Route-Specific Middleware

You can also apply middleware to specific routes, affecting the sequence for those routes.

app.use((req, res, next) => {
console.log('Global Middleware');
next();
});
app.get('/home', (req, res, next) => {
console.log('Route-Specific Middleware for /home');
next(); // Pass to the next middleware or route handler
}, (req, res) => {
res.send('Home Page');
});
app.listen(3000, () => {
console.log('Server running on port 3000');
});

What Happens?

  1. Global Middleware β†’ Logs: Global Middleware
  2. Route-Specific Middleware for /home β†’ Logs: Route-Specific Middleware for /home
  3. Route Handler for /home β†’ Sends: Home Page

2.3 Order with Error Handling Middleware

If any route or middleware passes an error to next(err), the error handling middleware will run.

app.use((req, res, next) => {
// Some logic...
next(new Error('Something went wrong!')); // Pass error to error handler
});
// Error handling middleware
app.use((err, req, res, next) => {
console.error('Caught an error:', err.message);
res.status(500).send('Internal Server Error');
});

What Happens?

  1. Middleware or route will pass an error via next().
  2. The error-handling middleware will catch the error and send an appropriate response.

2.4 Summary

  1. Global Middleware: Executed in the order they’re defined with app.use().
  2. Route-Specific Middleware: Executed in the order they are defined for specific routes (e.g., app.get(), app.post()).
  3. Error Handling Middleware: Activated only when an error is passed using next(err). It must have 4 parameters: (err, req, res, next).

3. Scope of Middleware

In Express.js, middleware functions are used to handle requests and responses. There are two main types in terms of scope: application-wide middleware and router-level middleware.

3.1 βœ… Application-wide Middleware

These are middleware functions that are applied to the entire app. They run for every incoming request, unless filtered by a path.

πŸ’‘ How it’s defined:
const express = require('express');
const app = express();
// Application-wide middleware
app.use((req, res, next) => {
console.log('This runs for all routes');
next();
});
πŸ“ You can also limit it to a specific path:
app.use('/api', (req, res, next) => {
console.log('This runs for all routes starting with /api');
next();
});

3.2 βœ… Router-level Middleware

This middleware is tied to an instance of express.Router(). It’s like a mini-app with its own middleware stack, and it’s mounted onto the main app at a certain path.

πŸ’‘ Example:
const express = require('express');
const app = express();
const router = express.Router();
// Router-level middleware
router.use((req, res, next) => {
console.log('Router-level middleware');
next();
});
// Routes inside the router
router.get('/hello', (req, res) => {
res.send('Hello from router!');
});
// Mount the router at /api
app.use('/api', router);

In this example, router.use() middleware will only apply to routes handled by that router (/api/hello, etc.).

3.3 πŸ” Summary Table

Middleware TypeScopeDefined UsingApplied To
Application-wideWhole appapp.use()All routes (or filtered by path)
Router-levelSpecific routerrouter.use()Only routes handled by that router