Express Next Argument in middleware functions

When working out a simple expressjs project for the first time there is starting out with some very basic hello world type examples that involve just a single middleware function attached for a single path of a project. When doing so there is a request object and response object that are both given as arguments for the middleware function. These two objects are useful for working with an http request, as well as creating and sending a response for that request. However there is another typical parameter for these functions that is the express next middleware parameter. This parameter of a middleware function is a function that can be called to allow for express to continue to the next middleware function to be called. The next middileware function can be the next function in an array of functions rather than just a single function, however in other cases it can result in continuing to a whole other path pattern in the main app.js file also.

So then in this post I will be going over a few simple examples of the next argument that is used in middleware design for expressjs projects. In the process of doing so I will also be touching base on a whole bunch of other expressjs, and nodejs related topics.

1 - Basic express next example

First off lets start with a very sime example of the next argument. Say that I set up a middleware for a path using the app.get method like in so many simple hello world express.js examples. However this time I am not passing just a single function for the middleware of a path, but an array of functions, and the path is an asterisk. So then because I am using an asterisk for the path this means that this middleware will apply for a get request at any path, and on top of that this is an array of functions that will be called in order.

So then when a request is received for this, the first function in the array will be called, at which point the next function can be called to continue on to the next function in the array.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
let express = require('express'),
app = express();
app.set('port', process.argv[2] || process.env.PORT || 8080);
app.get('*', [
// log request url to the console
(req, res, next) => {
console.log(req.url);
next();
},
// send hello message
(req, res) => {
res.send('Hello User');
}
]);
// listen on app port
app.listen(app.get('port'), () => {
console.log('app up on port: ' + app.get('port'));
});

2 - Send a favicon example

In the first example I have noticed that one of the paths that a browser will request on its own is a favicon, so then this can prove as a decent additional example of the next function. Say that I have more or less the same example as before, but now I want to send a favicon.ico file for requests for such a file. For this I can add an addition function in my array of functions, and check the req.url prop of the request object to see if the resource being requested is a favicon. In the event that it is I can respond with such a file by making use of the send file response method. For all other requests I can just call next again.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
let express = require('express'),
path = require('path'),
app = express();
app.set('port', process.argv[2] || process.env.PORT || 8080);
app.get('*', [
// log request url to the console
(req, res, next) => {
console.log(req.url);
next();
},
// send favicon file
(req, res, next) => {
// if the request is for /favicon, send a favicon.ico file for the request
if(req.url.toLowerCase() === '/favicon.ico'){
res.sendFile( path.join(__dirname, 'favicon.ico') );
}else{
next();
}
},
// send hello message
(req, res) => {
res.send('Hello User');
}
]);
// listen on app port
app.listen(app.get('port'), () => {
console.log('app up on port: ' + app.get('port'));
});

There are many more ways to go abut sending the favicon, for example if I place the favicon file at the root path of a public folder I can use the express static built in middleware as a way to serve the file, and any and all other files in the public folder. However in the event that I am doing something where there is no public folder, or I am doing something where there are only a few pubic folders for a few paths, then something like this might be needed as a way to host that file.

3 - The user agent header.

Maybe another good example would be to use an array of functions to preform all of the above, but also attach a special property to a request object that can then be used at a later point to do something deferent depending on the state of some kind of request header.

For this example I took my array of functions and placed it into its own file and called it all_requests.js, to which I then intend to use in my main app.js file with the app.all method. In this new array of functions I am checking the user agent string of the incoming request and using that to set a platform property of the request object.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
let path = require('path');
module.exports = [
// log request url to the console
(req, res, next) => {
console.log(req.url);
next();
},
// send favicon file
(req, res, next) => {
// if the request is for /favicon, send a favicon.ico file for the request
if(req.url.toLowerCase() === '/favicon.ico'){
res.sendFile( path.join(__dirname, 'favicon.ico') );
}else{
next();
}
},
// set a req.platform prop based on user agent header
(req, res, next) => {
var userAgent = req.get('user-agent');
// default to an 'Unkown platform'
req.platform = 'Unkown';
if(userAgent.match(/\(X11/)){
req.platform = 'Linux';
}
if(userAgent.match(/\(Windows/)){
req.platform = 'Windows';
}
if(userAgent.match(/\(Macintosh/)){
req.platform = 'Macintosh';
}
next();
}
];

I can then use this request_all.js file in my main app.js file like this.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
let express = require('express'),
path = require('path'),
app = express();
app.set('port', process.argv[2] || process.env.PORT || 8080);
// use all_requests.js for '*' path
app.all('*', require( path.join(__dirname, 'all_requests.js') ))
app.get('/', (req, res) => {
res.send('Hello ' + req.platform + ' OS User');
});
// listen on app port
app.listen(app.get('port'), () => {
console.log('app up on port: ' + app.get('port'));
});

There are better ways of going about doing this sort of thing by making a Router in the request_all.js file and using the app.use method in the main app.js file. However for the most part this is the basic idea of creating my own middleware modules.

4 - Conclusion

That is it for the express next argument, helpful this helps to gain some insight on how to go about making some half way decent middleware modules and scripts using express and nodejs.