Using Express Middleware

We look at how to use app and route-level middleware

John Au-Yeung
Feb 12 · 4 min read
Photo by Connor Dugan on Unsplash

“Middleware functions are functions that have access to the request object (req), the response object (res), and the next middleware function in the application’s request-response cycle.” — Express docs

In this piece, we’ll look at what Express middleware functions doe and how we can use them.


Characteristics of Middleware

Middleware functions can run any code, make changes to the request and response objects, end the request-response cycle, and call the next middleware in the stack.


Application-Level Middleware

We can run middleware functions used when any routes are called by passing them to the app.use method as a callback.

If we want to a middleware function to be called only when a request of one request method is called, then we can pass it to the app.METHOD method as a callback, where METHOD is get, post, put, delete, etc.

For example, we can write a middleware function and pass it into app.use to log the request method of a request, as follows:

const express = require('express')
const app = express()
app.use(express.json())
app.use(express.urlencoded({ extended: true }))
app.use((req, res, next) => {
console.log(req.method);
next();
});
app.get('/', (req, res) => {
res.json();
})
app.listen(3000, () => console.log('server started'));

Then we should get GET logged when we make a GET request to / .

We can restrict the middleware function to be run only on GET requests and to the path / by writing:

const express = require('express')
const app = express()
app.use(express.json())
app.use(express.urlencoded({ extended: true }))
app.get('/', (req, res, next) => {
console.log(req.method);
next();
});
app.get('/', (req, res) => {
res.json();
})
app.post('/', (req, res) => {
res.json();
})
app.listen(3000, () => console.log('server started'));

Then, we only see GET logged when we make GET requests to the / path.


Running a Series of Middleware Functions

We can use the next method to call the next middleware function in the series, so we can use it to chain middleware-function calls together.

For example, if we have …

const express = require('express')
const app = express()
app.use(express.json())
app.use(express.urlencoded({ extended: true }))
app.use(
(req, res, next) => {
console.log('middleware 1 called');
next();
},
(req, res, next) => {
console.log('middleware 2 called');
next();
}
);
app.get('/', (req, res) => {
res.json();
})
app.listen(3000, () => console.log('server started'));

… then we see from the console.log output of each middleware:

middleware 1 called
middleware 2 called

If we send a response in our middleware, then the next one won’t get called. For example, if we have:

const express = require('express')
const app = express()
app.use(express.json())
app.use(express.urlencoded({ extended: true }))
app.get('/',
(req, res, next) => {
next()
},
(req, res, next) => {
res.send('Second middleware');
}
)
app.get('/', (req, res, next) => {
res.end();
})
app.listen(3000, () => console.log('server started'));

Then, we get the output ‘Second middleware’ when we make a request to /.

Our route handler in …

app.get('/', function (req, res, next) {
res.end();
})

… wasn’t called.

We can call next, as follows, to go straight to our route handler, bypassing the other middleware functions down the line:

next('route');

For example, if we have:

const express = require('express')
const app = express()
app.use(express.json())
app.use(express.urlencoded({ extended: true }))
app.get('/:id',
(req, res, next) => {
if (req.params.id === '0') {
next('route');
return;
}
next();
},
(req, res, next) => {
res.send('Second middleware');
}
)
app.get('/:id', (req, res, next) => {
res.end(req.params.id);
})
app.listen(3000, () => console.log('server started'));

Then, when we make a request to /0 , we get 0 . Otherwise, we get ‘Second Middleware’ outputted.


Router-Level Middleware

Router-level middleware works the same way as app-level middleware, but they’re bound to the instance of the express.Router() instead of the express instance.

For example, we can use it as follows:

const express = require('express')
const app = express()
const router = express.Router();
app.use(express.json())
app.use(express.urlencoded({ extended: true }))
router.use((req, res, next) => {
req.requestTime = new Date();
next();
})
router.get('/', (req, res, next) => {
res.json(req.requestTime);
})
app.use('/', router);app.listen(3000, () => console.log('server started'));

Then when we make a request to the / route, we get back the timestamp as the output.

Chaining middlewares and skipping routes work the same way as app-level middleware. For example, we can write the following to chain middlewares:

const express = require('express')
const app = express()
const router = express.Router();
app.use(express.json())
app.use(express.urlencoded({ extended: true }))
router.use(
(req, res, next) => {
console.log('middleware 1 called');
next();
},
(req, res, next) => {
console.log('middleware 2 called');
next();
}
)
router.get('/', (req, res, next) => {
res.json();
})
app.use('/', router);app.listen(3000, () => console.log('server started'));

Then we see from the console.log output of each route middleware:

middleware 1 called
middleware 2 called

We can use next('route') to skip to the route, as follows:

const express = require('express')
const app = express()
const router = express.Router();
app.use(express.json())
app.use(express.urlencoded({ extended: true }))
router.get('/:id',
(req, res, next) => {
if (req.params.id === '0') {
next('route');
return;
}
next();
},
(req, res, next) => {
res.send('Second middleware');
}
)
router.get('/:id', (req, res, next) => {
res.end(req.params.id);
})
app.use('/', router);app.listen(3000, () => console.log('server started'));

Then when we make a request to /0, we get 0 . Otherwise, we get ‘Second Middleware’ outputted.


Conclusion

Using Express middlewares is simple. We can either pass them into app.use to make the middleware run for all request methods or app.METHOD to make them run for the given method.

We can call next to call the next middleware and call next('route') to call the route handler directly from a middleware.

Everything applies to both route and app-level middleware, except they bind to the express.Router() and express(), respectively.

Better Programming

Advice for programmers.

John Au-Yeung

Written by

Web developer. Subscribe to my email list now at http://jauyeung.net/subscribe/ . Follow me on Twitter at https://twitter.com/AuMayeung

Better Programming

Advice for programmers.

More From Medium

More from Better Programming

More from Better Programming

More from Better Programming

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade