Search code examples
asynchronousecmascript-6async-awaitmiddleware

Middleware transform to async/await


I started to learn ES6 and I'm transforming my project from ES5 to ES6. I want to ask if it's sense to use async/await in middlewares ? How to use it in this example :

middlewareObj.checkCampground = (req,res,next) =>{
if(req.isAuthenticated()){
    Campground.findById(req.params.id, (err, foundCampground) =>{
        if(err || !foundCampground){
            req.flash("error", "Campground not found");
            res.redirect("back");
        } else {
            if(foundCampground.author.id.equals(req.user._id) || req.user.isAdmin){
                next();
            } else {
                req.flash("error", "You don't have permission to do that");
                res.redirect("back");
            }
        }
    });
} else {
    req.flash("error", "You need to be logged in to do that");
    res.redirect("back");
}

};


Solution

  • When you only have a single asynchronous operation like you do here, you don't gain much (if anything) from switching to await. The bigger benefits come when you need to sequence multiple asynchronous operations and perhaps even have some branching. Then await lets you write much simpler code.

    Plus, most of your code here is really just about checking results and getting the right error message back to the user and that doesn't get a lot simpler with await as it's just a bunch of rote checks either way.

    Here's an implementation that also attempts to use exceptions to consolidate all the error returns so you don't have as many places where you're doing req.flash() and res.redirect():

    middlewareObj.checkCampground = async (req,res,next) => {
        try {
            if(req.isAuthenticated()) {
                throw new Error("You need to be logged in to do that");
            }
            const foundCampground = await Campground.findById(req.params.id);
            if (!foundCampground) {
                throw new Error("Campgound not found")
            }
            if (foundCampground.author.id.equals(req.user._id) || req.user.isAdmin) {
                next();
            } else {
                throw new Error("You don't have permission to do that");
            }
    
        } catch(e) {
            console.log(e);
            req.flash(e.message);
            res.redirect("back");
        }
    };
    

    Here's another alternative without async/await that just attempts to consolidate the error handling a bit. You can't get around the fact that there are three if checks and four possible errors:

    middlewareObj.checkCampground = (req,res,next) => {
        function error(msg, location = "back") {
            req.flash(msg);
            res.redirect(location);
        }
    
        if(req.isAuthenticated()) {
            error("You need to be logged in to do that");
            return;
        } 
        Campground.findById(req.params.id).then(foundCampground => {
            if (!foundCampground) {
                error("Campground not found");
            } else if (foundCampground.author.id.equals(req.user._id) || req.user.isAdmin) {
                next();            
            } else {
                error("You don't have permission to do that");
            }
        }).catch(err => {
            console.log(err);
            error("Database Error - Campground not found");
        });
    };
    

    Note that in both of these, I make sure and log an actual database error if there is one.