Making your own Express Middleware

Johnny Simpson - Jun 19 '22 - - Dev Community

Express is a common way to display static routes to a user. It is even more commonly used to create APIs for Node.JS. In Express, it's easy to define a URL, and what will happen at that URL. We can also define middleware, which runs before the final request is returned. This can let us to alter the request, and do it in a standard way across many routes.

If you've used Express, you may have already used pre-built middlewares like bodyParser or jsonParser. In this guide, let's look at how you can create your own custom middleware.

Creating a middleware in Express

A middleware is simply something which data passes through on its way to its actual end location. Consider you have a route like this:

import express from 'express';
const app = express()

app.get('/home/', (req, res, next) => {
    if(req.getRoute == true) {
        res.status(200).send("Hello world!")
    }
    else {
        res.status(200).send("Goodbye world!")
    }
})
Enter fullscreen mode Exit fullscreen mode

In this example, if the request or req has the property getRoute set to true, we will show a different set of text. By default, HTTP requests do not have a property called getRoute. Of course, it would be easy to set it within /home/ itself, but imagine you had multiple requests, all depending on this one getRoute property:

import express from 'express';
const app = express()

app.get('/home/', (req, res, next) => {
    if(req.getRoute == true) {
        res.status(200).send("Hello world!")
    }
    else {
        res.status(200).send("Goodbye world!")
    }
})

app.get('/home/article', (req, res, next) => {
    if(req.getRoute == false) {
        res.status(200).send("This is my article");
    }
    else {
        res.status(400).send("ERROR OCCURRED");
    }
})
Enter fullscreen mode Exit fullscreen mode

Now we have a situation where a middleware might make sense. There are two ways to define a middleware - with use(), or via a function. Let's look at use() first.

use() as a middleware

Considering our previous example, we can use use() to write a function that runs on every route. This is therefore a general middleware, which will run any time the user goes to any valid route on your server. Here is an example, where we define getRoute within a use() middleware:

app.use((req, res, next) => {
    // Add getRoute to our request object
    req.getRoute = true;
    // Next tells express to now go to the next valid function.
    next();
});

app.get('/home/', (req, res, next) => {
    if(req.getRoute == true) {
        res.status(200).send("Hello world!")
    }
    else {
        res.status(200).send("Goodbye world!")
    }
})

app.get('/home/article', (req, res, next) => {
    if(req.getRoute == false) {
        res.status(200).send("This is my article");
    }
    else {
        res.status(400).send("ERROR OCCURRED");
    }
})
Enter fullscreen mode Exit fullscreen mode

Using this middleware, we can add getRoute to our request, and it'll now be available to /home/ and /home/article. It'll also be available to any other route on your server. When we call next(), it tells Express to go onto the next valid route. For example, if the user went to /home/, then first our middleware would be called, and then since we called next() within it, Express would go to the /home/ route, as we have it defined.

Use case: API Verification

A trick I often use for generalised middlewares is to split functionality that applies to certain HTTP methods. For example, if I wanted to apply an API verification function to all POST requests, I can easily do that in a standard middleware used by the entire app:

import { apiVerification } from './util.js'
app.use(async (req, res, next) => {
    // Here, apiVerification is a function that returns true if the right request is sent.
    // We only want to apply it to POST methods, though, so lets add that to our middleware.
    if(req.method == "POST") {
        let verifyCredentials = await apiVerification(req);
        if(verifyCredentials) {
            next();
        }
        else {
            res.status(400).send("ERROR OCCURRED");
        }
    }
    else {
        // For everything else, like "GET", go to next valid route.
        next();
    }
});
Enter fullscreen mode Exit fullscreen mode

This is a perfect way to add a standard verification method to all your POST routes, without having to redefine and recall apiVerification every time. If apiVerification fails, the user is given an error message instead. For other methods like GET, this apiVerification step is skipped is skipped.

Specific Middlewares

Sometimes, you only want a middleware to apply to specific routes, rather than generally to everything. For that, we need to define them in a function. Using our previous example, we can create a function for req.getRoute, and apply it to only the routes we want to:

let setGetRoute = (req, res, next) => {
    req.getRoute = true;
}

app.get('/home/', setGetRoute, (req, res, next) => {
    if(req.getRoute == true) {
        res.status(200).send("Hello world!")
    }
    else {
        res.status(200).send("Goodbye world!")
    }
})

app.get('/home/article', (req, res, next) => {
    if(req.getRoute == undefined) {
        res.status(200).send("This is my article");
    }
    else {
        res.status(400).send("ERROR OCCURRED");
    }
})
Enter fullscreen mode Exit fullscreen mode

Now req.getRoute will only be available to app.get('/home/'.., since we only added that function to that route (app.get('/home/', setGetRoute...). For /home/article, req.getRoute will not be available.

This is quite useful when we only want to provide certain functionality in specific situations.

Conclusion

Middlewares are a powerful part of Express, and let us process requests differently, or apply certain functions to all requests. I hope you've enjoyed this article. To learn more about Javascript, click here.

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .