Middleware functions are used to process requests, execute common tasks, modify request or response objects, and control how requests move through an Express.js application.
Middleware is a function that runs during the request-response cycle. It can execute code, read or modify request information, end the response, or pass control to another middleware function.
For example, middleware can be used to:
Log request details
Check request or user
Process the requested URL
A basic middleware function looks like this:
function myMiddleware(req, res, next) {
console.log('Middleware executed');
next();
}
req contains information about the incoming request.res is used to send a response.next() passes control to the next middleware or route handler.
Create a file named app.js and add the following code.
const express = require('express');
const app = express();
app.use((req, res, next) => {
console.log('Middleware is running');
next();
});
app.get('/', (req, res) => {
res.send('Welcome to Express.js');
});
app.listen(3000, () => {
console.log('Server running on port 3000');
});
Run the application:
node app.js
Open http://localhost:3000.
Terminal output after a request:
Server running on port 3000
Middleware is running
The middleware runs before the matching route handler. Additional browser requests may produce additional log messages.
Application-level middleware is registered on the Express
application using app.use() or an HTTP-method
route method such as app.get().
const express = require('express');
const app = express();
app.use((req, res, next) => {
console.log(
req.method + ' ' + req.url
);
next();
});
app.get('/', (req, res) => {
res.send('Home Page');
});
app.get('/about', (req, res) => {
res.send('About Page');
});
app.listen(3000, () => {
console.log('Server started');
});
When you visit /about, the terminal logs:
GET /about
This is useful for basic request logging and debugging.
Route-level middleware is applied to a particular route instead of every request handled by the application.
const express = require('express');
const app = express();
function checkAccess(req, res, next) {
console.log('Checking access');
next();
}
app.get('/public', (req, res) => {
res.send('Public Page');
});
app.get('/dashboard', checkAccess, (req, res) => {
res.send('Dashboard Page');
});
app.listen(3000, () => {
console.log('Server started');
});
Visiting /dashboard runs
checkAccess() before the route handler.
Visiting /public does not run this middleware.
Middleware does not always need to call next().
It can send a response and stop further processing.
const express = require('express');
const app = express();
function blockRequest(req, res, next) {
res.status(403).send('Access Denied');
}
app.get('/restricted', blockRequest, (req, res) => {
res.send('Restricted Page');
});
app.listen(3000, () => {
console.log('Server started');
});
Open:
http://localhost:3000/restricted
The route handler does not run because the middleware has already sent the response.
Express provides built-in middleware for common tasks such as parsing JSON requests and serving static files.
| Middleware | Purpose |
|---|---|
express.json() |
Parses incoming JSON request bodies. |
express.urlencoded() |
Parses URL-encoded form request bodies. |
express.static() |
Serves static files such as CSS, images, and JavaScript. |
When a client sends JSON data in a POST request,
express.json() can parse the request body so that
it is available through req.body.
const express = require('express');
const app = express();
app.use(express.json());
app.post('/student', (req, res) => {
const student = req.body;
res.json({
message: 'Student data received',
student: student
});
});
app.listen(3000, () => {
console.log('Server started');
});
Send a POST request to /student with this JSON body:
{
"name": "Amit",
"course": "Node.js"
}
Example response:
{
"message": "Student data received",
"student": {
"name": "Amit",
"course": "Node.js"
}
}
Content-Type header to
application/json.
HTML forms commonly send URL-encoded data. Express can parse
this data with express.urlencoded().
const express = require('express');
const app = express();
app.use(express.urlencoded({ extended: false }));
app.post('/register', (req, res) => {
const name = req.body.name;
res.send('Welcome, ' + name);
});
app.listen(3000, () => {
console.log('Server started');
});
This middleware parses URL-encoded request bodies.
The submitted form data can then be accessed through
req.body.
Static middleware serves files directly from a folder. It is commonly used for CSS, images, browser-side JavaScript, and HTML files.
my-app/
│
├── app.js
└── public/
├── style.css
└── logo.png
const express = require('express');
const app = express();
app.use(express.static('public'));
app.listen(3000, () => {
console.log('Server started');
});
With this configuration, you can access:
http://localhost:3000/style.csshttp://localhost:3000/logo.png
The folder name public is not included
in the public URL by default.
Express supports special error-handling middleware that receives an error object as its first argument.
const express = require('express');
const app = express();
app.get('/error', (req, res, next) => {
next(new Error('Something went wrong'));
});
// Error-handling middleware
app.use((err, req, res, next) => {
console.error(err.message);
res.status(500).send('Internal Server Error');
});
app.listen(3000, () => {
console.log('Server started');
});
Open http://localhost:3000/error to test it.
(err, req, res, next). In production,
avoid exposing sensitive internal error details to clients.
Express processes middleware in the order in which it is registered, provided that the request matches the middleware and control is passed onward.
const express = require('express');
const app = express();
app.use((req, res, next) => {
console.log('Middleware 1');
next();
});
app.use((req, res, next) => {
console.log('Middleware 2');
next();
});
app.get('/', (req, res) => {
console.log('Route Handler');
res.send('Hello Student');
});
app.listen(3000, () => {
console.log('Server started');
});
When you visit the home page, the log order is:
Middleware 1
Middleware 2
Route Handler
| Mistake | How to Fix It |
|---|---|
Forgetting to call next() |
Call next() when continuing without sending a response. |
| Sending a response more than once | End the response in one appropriate path. |
Using req.body before parsing JSON |
Register express.json() before the relevant routes. |
| Registering error middleware before routes | Usually place error-handling middleware after the routes that may pass errors to it. |
| Assuming logging is authentication | Use proper authentication and authorization checks for protected resources. |
Create an Express application with these requirements:
/dashboard route with route-level middleware.express.json() to receive JSON data.express.static() to serve a CSS file from a public folder.Select the correct answer for each question.