Express.js Middleware in Javascript
What is middleware?
Middleware allows you to interact with the request and response object in your code. As the name suggests, it comes in the middle to provide services to applications. In the middle of what though? Well, I’ll let this illustration explain that to you.
Middlewares are capable of changing requests, response objects, and can end the response cycle as well. For simplicity, you can think of middleware as a group of functions that will execute whenever a request to the server has been made.
Why use middleware?
On most websites, any time you interact with the browser, it requests information from a web server. The web server then sends a response back to the browser which it then converts and shows it to you as text, image, video, etc.
When the web-server receives a request,
Express
(
a web-application server framework for node.js
) gives you a
request
object where you can see the data they are requesting along with some user details such as IP address, browser language, passed parameters, etc. Express also gives you access to a
response
object. These objects are usually shortened to
req
,
res
.
Let’s take an example. Assume a user visited your website and logged in with some credentials. Now a
request
object has been sent to your web server. You need to authenticate the user and also log into the database that
<user>
signed in at the given
<time>
with the <
used device>
and <
IP>
before sending the
response
object back to the browser. Moreover, you also need to check the database to find the page of your website that the user browsed the last time he/she used it and modify the
request
object to let him/her continue from there. How do you do that? You use middleware functions!
Middleware functions are the perfect place to modify the
req
and
res
objects. For instance, here, once the user has signed in, you can authenticate the user from the database and then update his details in
res.user
.
Middleware gives you access toreq
andres
objects in the app’s request-> response cycle.
Middleware functions can perform the following tasks:
- Execute any code.
- Make changes to the request and the response objects.
- End the request-response cycle.
-
Call the next middleware in the stack using
next()
What is next()?
As mentioned earlier middleware can be assumed as a group of functions whenever a request has been made to the server. Well, since it is a group of functions, how is the order in which they execute be decided? and how will the execution flow be maintained? Firstly, the order of execution is decided by the order of loading of functions. For a basic code, we will just load the functions in
app.get().
Here is a simple example →
app.get('/', authenticate, log_data, update_req);
Now the ordering of middleware functions is decided → authenticate(), log_data() and then update_req().
But how will the flow of execution go from one middleware function to another? Well, this is when the
next()
function comes into the picture.
A middleware function typically receives three arguments:
req
,
res
and
next
.
next
is the next function which will be executed after the current one.
If the current middleware function does not end the request-response cycle, it must call
next()
to pass control to the next middleware function. Otherwise, the request will be left hanging.
For example, in the above case, our function orders are
authenticate()
, then
log_data()
and then
update_req()
The code for the middleware will then look something like this →
const authenticate = function (req, res, next) {
// code to authenticate user
next();
}
const log_data = function(req, res, next) {
// code to log signin data in database
next();
}
const update_req = function(req, res, next) {
// code to update req object
}
The next function can be named otherwise too but this is the convention followed to avoid any confusion.
Note:
Using
next()
in the last function(update_req) is optional and won’t do anything since it is the last function in the request-response cycle.
We don’t always load the functions in the arguments of
app.get()
. We can also use
app.use()
,
route.use()
, etc.
Coding Middleware
You can code your middleware in several ways. You can also use third-party middleware functions if you want. First of all, you need to load your middleware function. There are two basic ways to do that →
- Load it as parameters in app.get() as shown above
-
Load it using
app.use()
. This is a conventional and better way.
app.get()
is called only when the HTTP method used in the request is
GET
whereas loading a function via
app.use()
means it will be called every time a request is made to the application(doesn’t matter what the HTTP method is). Therefore,
app.use()
is considered a better way to load the middleware.
Updating the code above using the 2nd technique, it will look something like this →
const authenticate = function (req, res, next) {
// code to authenticate user
next();
}
app.use(authenticate);
const log_data = function(req, res, next) {
// code to log signin data in database
next();
}
app.use(log_data);
const update_req = function(req, res, next) {
// code to update req object
}
app.use(update_req);
app.get('/');
Here, the order of functions is decided in the order they are loaded, which is first
authenticate
, the
log_data,
and then
update_req
.If you use built-in or third-party middleware, just import the function and load it using
app.use()
. A commonly used built-in middleware is
cookie-parser
. It is used to parse cookie header and populate req.cookies. You can include this in your code very easily →
const cookie_parser = require('cookie-parser');
app.use(cookie_parser());
You can find some commonly used built-in express middleware functions here .
Conclusion
Middleware is a great tool to organize your code to work in the request-response cycle. It is basically a function that has access to the
req
and
res
objects of your application. It can be thought of as a series of tasks that the developer performs before the request is handled by the application. You can code your own middleware functions or use built-in or 3rd party functions.
Please comment with your feedback below.