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
orres
- 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
Middleware | Purpose |
---|---|
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:
- Application-level β applies to all routes
- Route-level β applies only to specific routes
- Error-handling β catches and handles errors
- Built-in or third-party β like
cors
,body-parser
,morgan
1.4 π§΅ Example Flow
app.use(express.json()); // 1: parse JSONapp.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.
-
Global Middleware
- Middleware registered with
app.use()
or specific routes will run in the order they are defined in your code.
- Middleware registered with
-
Route-Specific Middleware
- Middleware attached to specific routes (like
app.get()
,app.post()
, etc.) runs in the order it is defined for that route.
- Middleware attached to specific routes (like
-
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)
.
- Middleware that handles errors is called only if an error is passed to
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.
- If you define middleware
-
2. Call
next()
to move forward: After each middleware runs, it needs to callnext()
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 middlewareapp.use((req, res, next) => { console.log('First middleware'); next(); // Pass to next middleware});
// Second middlewareapp.use((req, res, next) => { console.log('Second middleware'); next(); // Pass to next middleware});
// Route handlerapp.get('/', (req, res) => { res.send('Hello World');});
// Error handling middlewareapp.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?
- First Middleware β Logs:
First middleware
- Second Middleware β Logs:
Second middleware
- Route Handler (
GET /
) β Sends:Hello World
- 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?
Global Middleware
β Logs:Global Middleware
Route-Specific Middleware for /home
β Logs:Route-Specific Middleware for /home
- 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 middlewareapp.use((err, req, res, next) => { console.error('Caught an error:', err.message); res.status(500).send('Internal Server Error');});
What Happens?
- Middleware or route will pass an error via
next()
. - The error-handling middleware will catch the error and send an appropriate response.
2.4 Summary
- Global Middleware: Executed in the order theyβre defined with
app.use()
. - Route-Specific Middleware: Executed in the order they are defined for specific routes (e.g.,
app.get()
,app.post()
). - 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 middlewareapp.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 middlewarerouter.use((req, res, next) => { console.log('Router-level middleware'); next();});
// Routes inside the routerrouter.get('/hello', (req, res) => { res.send('Hello from router!');});
// Mount the router at /apiapp.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 Type | Scope | Defined Using | Applied To |
---|---|---|---|
Application-wide | Whole app | app.use() | All routes (or filtered by path) |
Router-level | Specific router | router.use() | Only routes handled by that router |