Optimizing Express Middleware: Passing Data via req to Avoid Extra DB Queries

Mohammad AfnanMohammad Afnan
2 min read

Background

so i am currently working on a youtube clone backend project which i started to understand backend development and express better. i have had made the architecture in the standard form like controller in one directory , models in one directory, etc but i was thinking of scaling the project which made me discover component based architecture and i started to migrate my architecture which made me call database multiple times like in the validator to verify if the video is present or not and in the main service to delete the old thumbnail from the cloud because the file url is in the database which made the request a bit slower although it is mili seconds for me because i have a fast internet speed but if the slow then it would become a burdun

Solution

While i was searching how to reduce the db calls, i found great way, here is an example

// code with the 3 db calls (2 for findById and 1 for findByIdAndDelete ) 
const validationMiddleware = async (req, _, next) => {
    try {
        const video = await Video.findById(req.params.videoId);
        if (!video) throw new Error(404, "Video not found")
        // more validation logic here

        next()
    }
    catch (e) { 
        console.log("error in video validation %O ", e) 
    }
}

const deleteVideoController = async (req, res) => {
    try {
        const video = await Video.findById(req.params.videoId);
        if (video.thumnail) await myDeleteThumbnailFunc(video.thumbnail);
        await Video.findByIdAndDelete(req.params.videoId);

        res.status(204).end()
    } catch (e) {
        throw new Error(500, "Internal Server Error, failed to delete video " )
    }
}

app.delete("/video/:videoId", validationMiddleware, deleteVideoController);

// solution with 2 db calls ( 1 for findById and 1 for findByIdAndDelete ) 

const validationMiddleware = async (req, _, next) => {
    try {
        const video = await Video.findById(req.params.videoId);
        if (!video) throw new Error(404, "Video not found");
        // more validation logic here

        req.videoMeta = video;
        next();
    }
    catch (e) { 
        console.log("error in video validation %O ", e);
    }
}

const deleteVideoController = async (req, res) => {
    try {
        const video = req.videoMeta;
        if (video.thumnail) await myDeleteThumbnailFunc(video.thumbnail);
        await Video.findByIdAndDelete(req.params.videoId);

        res.status(204).end()
    } catch (e) {
        throw new Error(500, "Internal Server Error, failed to delete video " )
    }
}

app.delete("/video/:videoId", validationMiddleware, deleteVideoController);

In the solution, the video data which was validating in the vaildationMiddleware is populated in the req variable, which helps to make data flow between the middleware and a controller, it can also be used for data flow between two middlewares too, and you can also assign your variables to req.locals.variable too as per [express docs](https://expressjs.com/en/5x/api.html#res.locals)

And this is how is fixed my problem, i hope you learned something new from this blog :)

0
Subscribe to my newsletter

Read articles from Mohammad Afnan directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Mohammad Afnan
Mohammad Afnan