Skip to content

Error: Route.post() requires a callback function but got a [object Promise]

I am creating a REST API with express, folowing are my architecture,a router is calling a controller.but I got this error, please help me

Error: Route.post() requires a callback function but got a [object Promise]

/////// EmailLogin.js middleware Handler

const { validationResult } = require('express-validator');


   let wrapRoute = async (req, res, next) => {
  try {
      // run controllers logic
      await fn(req, res, next)
  } catch (e) {
      // if an exception is raised, do not send any response
      // just continue performing the middleware chain
      next(e)
  }
}




const EmailLogin = wrapRoute(async (req, res) => {

    const errors =  validationResult(req);
    if (!errors.isEmpty()) {
    return res.status(422).json({ errors: errors.array() });

    } else {

  var gtoken = req.body.gtoken;
  var gSecretKey = env.secret_key;
   
    if (!gtoken) throw new Error('no token')

    const captchaURL = `https://www.google.com/recaptcha/api/siteverify?secret=${gSecretKey}&response=${gtoken}`
 
    await  axios({
      url: captchaURL,
      method: 'POST',
      headers: {ContentType: 'application/x-www-form-urlencoded'},
  
    }).then(response => {
    
      const gVerifyData = response.data
      if (gVerifyData.success === true) {
       Users.findOne({'email': req.body.email}).select('+hashPassword +status').exec(function (err, user)  {

          if(err){
              return res.status(500).send({err});
            } else if (user) {
           
              validPassword = bcrypt.compareSync(req.body.password, user.hashPassword);

              if (!validPassword){

                return res.send("wrong-info");
             
              } else  if (validPassword && user.status == "active")  {
          
                token = jwt.sign({ id: user._id }, env.jwtsecret, 
                { expiresIn: "168h" });
                res.status(200).send({ token: token, user });

                }
            }  else {

              return res.send("wrong-info");
            
            }
            }
            )
          }else {
            return  res.status(500).send('bot');
          }
    }).catch(error =>  {
          console.log(error);
        
        });
      }
    });





    function errorHandler (err, req, res, next) {
      console.log(err);
      // If err has no specified error code, set error code to 'Internal Server Error (500)'
      if (!err.statusCode) {
          err.statusCode = 500;
      } 
      
      res.status(err.statusCode).json({
          status: false,
          error: err.message
      });
 
  };

module.exports = {EmailLogin};

I’m trying to call it in my router, like this:

/////// Router.js

const express = require('express');
const router  = express.Router();
const { check } = require('express-validator');

const EmailLoginController = require('../controllers/EmailLogin');


var emailLoginValidation = [
    check('email').notEmpty().trim().escape().isEmail(),
    check('password').notEmpty().isLength({ min: 7 }).withMessage('password is invalid'),
  ];



router.post('/email-login', emailLoginValidation, EmailLoginController.EmailLogin);


module.exports = router;

/////// App.js

var express = require("express");
var app = express();


const Router = require('./routes/Router');
app.use('/', Router); 


app.listen(3000, function() {
  console.log('listening on 3000');
  
});

What could I do ? is it possible to get a Promise Result in the Router as a Handler?

Answer

@turkdev Change your email login function to this

const EmailLogin = async (req, res, next) => {

    const errors = validationResult(req);
    if (!errors.isEmpty()) {
        return res.status(422).json({ errors: errors.array() });

    } else {

        var gtoken = req.body.gtoken;
        var gSecretKey = env.secret_key;

        if (!gtoken) throw new Error('no token')

        const captchaURL = `https://www.google.com/recaptcha/api/siteverify?secret=${gSecretKey}&response=${gtoken}`

        await axios({
            url: captchaURL,
            method: 'POST',
            headers: { ContentType: 'application/x-www-form-urlencoded' },

        }).then(response => {

            const gVerifyData = response.data
            if (gVerifyData.success === true) {
                Users.findOne({ 'email': req.body.email }).select('+hashPassword +status').exec(function (err, user) {

                    if (err) {
                        return res.status(500).send({ err });
                    } else if (user) {

                        validPassword = bcrypt.compareSync(req.body.password, user.hashPassword);

                        if (!validPassword) {

                            return res.send("wrong-info");

                        } else if (validPassword && user.status == "active") {

                            token = jwt.sign({ id: user._id }, env.jwtsecret,
                                { expiresIn: "168h" });
                            res.status(200).send({ token: token, user });

                        }
                    } else {

                        return res.send("wrong-info");

                    }
                }
                )
            } else {
                return res.status(500).send('bot');
            }
        }).catch(error => {
            console.log(error);

        });
    }
};

The problem was earlier, you were assigning it to method wrapRoute() which returns a Promise, which was not settled, causing the error which you got.

If that was just for calling next() on error, you could always use it in the catch block.