All you need to know about routing in the Express Framework for Node.js
Posted
Updated
Europe’s developer-focused job platform
Let companies apply to you
Developer-focused, salary and tech stack upfront.
Just one profile, no job applications!
This article is based on Node v16.14.0.
Express reduces complexity and makes developing and maintaining applications much easier than the built-in Node.js tools. Routing is one of three big concepts in the Express framework. Read more about Express.js in the Introduction to Express.js.
💰 The Pragmatic Programmer: journey to mastery. 💰 One of the best books in software development, sold over 200,000 times.
This article is part of a large series about Express.js. You can find all articles here - Express Framework.
Routing refers to how an application responds to a client request to a particular endpoint, which is a URI (or a path) and a specific HTTP request method (GET, POST, etc.). Each route can have one or more handler functions, which are executed when the route is matched.
A Route definition takes the following structure: app.METHOD(PATH, HANDLER)
app
is an instance of express.METHOD
is an HTTP request method, in lowercase.PATH
is a path on the server.HANDLER
is the function executed when the route is matched.Let's look at an example of a route /home
that is defined for a GET request.
const express = require('express');
const app = express();
// GET method route
app.get('/home', (req, res) => {
res.send('OK');
});
In the above example:
app
is an instance of Expressapp.get
is the HTTP request method/home
is the route(req, res) => {}
is the handler function, which runs in response to a matching request.A route method is derived from one of the HTTP methods, and is attached to an instance of the express class. There is a method for every HTTP verb, most commonly used below. For a full list see MDN.
.get()
.post()
.put()
.delete()
.patch()
There is a special routing method app.all()
.
It is used to load middleware functions at a path for all HTTP requests.
app.all('/secret', (req, res, next) => {
console.log('Accessing the secret section ...');
next(); // pass control to the next handler
});
Route paths with a request method define the endpoints at which requests can be made. They can be string, string patterns or regular expressions. Query strings are not part of the route path.
The characters ?, +, *, and () are subsets of their regular expression counterparts. The hyphen (-), and the dot (.) are interpreted literally by string-based paths.
Express uses path-to-regexp for matching the route paths, there are many possibilities, but also limitations in choosing routes. For a full list refer to the documentation of path-to-regexp.
Here are a few examples for routes:
This route path will match requests made to /
.
app.get('/', (req, res) => {
res.send('root');
});
This route path will match requests made to /home
.
app.get('/home', (req, res) => {
res.send('home');
});
This route path will match requests made to /info.text
.
app.get('/info.text', (req, res) => {
res.send('info.text');
});
This route path will match requests made to /acd
and /abcd
.
app.get('/ab?cd', (req, res) => {
res.send('ab?cd');
});
This route path will match requests made to abcd
, abbcd
, abbbcd
, etc.
app.get('/ab+cd', (req, res) => {
res.send('ab+cd');
});
This route path will match requests made to abcd
, abxcd
, abANYRANDOMSTRINGcd
, etc.
app.get('/ab*cd', (req, res) => {
res.send('ab*cd');
});
Since regular expressions are possible as route paths., this route path will match requests containing an a
anywhere.
app.get('/a/', (req, res) => {
res.send('/a/');
});
Express 4.x treats the *
differently, see here. This behaviour is fixed since Express 5.x.
A Route can accept dynamic values within a path, so called route parameters.
Route parameters are named URL segments that are used to capture the values specified at their position in the URL.
The captured values are populated in the req.params
object, with the name of the route parameter as their key.
For example a route path /users/:userId/books/:bookId
would require a request URL to be something like http://localhost:3000/users/34/books/8989
,
and the captured route parameters would be populated in req.params
like this { "userId": "34", "bookId": "8989" }
.
To define a route parameter just specify the route parameters in the path.
app.get(`/users/:userId/books/:bookId`, (req, res) => {
console.log(req.params);
});
Route handlers are callback functions or arrays of functions, which basically handle requests.
Multiple callback functions can be provided to handle a request and behave like a middleware.
The only exception is that these callbacks can call next()
to bypass the next and remaining route callbacks.
Route handlers can be in the form of a function, an array of functions, or a combination of both.
The request and response are often shortened to req
and res
, and stand for the request which was received by the server,
and the response which will eventually be send back.
These are based on built-in objects in Node.js, the ClientRequest and ServerResponse. There will be a dedicated Express routing blog post in the future.
A single HTTP transaction can be roughly described by the Request and Response cycle.
Augmenting the req
and res
objects is a big part of how Express enhances functionality,
while still maintaining control over how requests and responses are handled.
A single callback function can handle a route like this:
app.get('/home', (req, res) => {
res.send('home');
});
Below an array of functions example:
const cb0 = function(req, res, next) {
console.log('CB0');
next();
};
const cb1 = function(req, res, next) {
console.log('CB1');
next();
};
app.get('/c', [cb0, cb1]);
The methods on the response object (res) in the following table can send a response to the client, and terminate the request-response cycle. If none of these methods are called from a route handler, the client request will be left hanging.
res.download()
Prompt a file to be downloaded.res.end()
End the response process.res.json()
Send a JSON response.res.jsonp()
Send a JSON response with JSONP support.res.redirect()
Redirect a request.res.render()
Render a view template.res.send()
Send a response of various types.res.sendFile()
Send a file as an octet stream.res.sendStatus()
Set the response status code and send its string representation as the response body.app.route()
With app.route()
you can chain route handlers for a route path.
Creating modular routes is helpful, because it is reducing redundancy and typos.
Let's have a look at an example of chained route handlers:
app
.route('/book')
.get(function(req, res) {
res.send('Get a random book');
})
.post(function(req, res) {
res.send('Add a book');
})
.put(function(req, res) {
res.send('Update the book');
});
app.METHOD(PATH, HANDLER)
app.all()
is used to load middleware functions at a path for all HTTP requests.app.route()
Thanks for reading and if you have any questions, use the comment function or send me a message @mariokandut.
If you want to know more about Express, have a look at these Express Tutorials.
References (and Big thanks):
HeyNode, ExpressJS, Express - Routing, Express - Basic Routing, path-to-regexp
Never miss an article.