Pablo D
Pablo D

Reputation: 393

Nest multiple async await

I have the following Express endpoint:

const all = require('promise-all');

router.post('/verify', upload.single('photo'), async (req, res) => {
  ...    
  await all({'p1': p1, 'p2': p2}).then((response) => {
      ...
      console.log("Response:", 
      ruleCtrl.manageRule(detection, res);
  });
});

ruleCtrl.manageRuleis as follows:

export async function manageRule(identifierDetected, res) {
  let rule = db.getRule(identifierDetected);
  await all([rule]).then((ruleExtracted) => {
    ...
    res.json(ruleExtracted);
  }).catch((err) => {
    res.status(418).send("DOCUMENT_NOT_RECOGNIZED");
  });
}

and db.getRule:

export async function getRule(idRule) {
  return new Promise((resolve, reject) => {
    Rule.findOne({ruleID: idRule}, (err, rule) => {
        if (err) {
            reject("MongoDB Rule error: " + err);
        } else {
            resolve(rule);
        }
    });
  })
}

My response is into manageRule and this function depends of the values extracted into the await all. So, right now, Express is returning a response before get the information from mongoose database (db).

Which is the way to handle this issue?

Thanks everyone!

Upvotes: 2

Views: 1041

Answers (1)

lazreg87
lazreg87

Reputation: 953

I would refactor your code a bit to make it easier to read, and also return the result from ruleCtrl.manageRule(detection, res);. The request might simply be timing out since your original code is missing a return there or an await (to make sure it finishes executing)

Express endpoint:

const all = require('promise-all');

router.post('/verify', upload.single('photo'), async (req, res) => {
  ...
  // Catch any exceptions from the promises. This is the same as using .catch
  try {
    // Lets assign the returned responses to variable
    let [p1Result, p2Result] = await all({'p1': p1, 'p2': p2});
    ...
    console.log("Responses:", p1Result, p2Result);
    // return the response from manageRule method
    return ruleCtrl.manageRule(detection, res);
  } catch(err) {
    // Handle err here
  }
});

One of the great benefits with async await is moving away from chained promises, so simply return the result from the await to a variable instead of using .then()

ruleCtrl.manageRule

export async function manageRule(identifierDetected, res) {
  // Use try catch here to catch error from db.getRule. Assign to variable and return 
  // res.json  
  try {      
    let ruleExtracted = await db.getRule(identifierDetected);
    ...
    return res.json(ruleExtracted);
  } catch(err) {
    return res.status(418).send("DOCUMENT_NOT_RECOGNIZED");
  }
}

You dont have to return res.json or res.status here, I just like to keep track of when I want to end function execution.

You could refactor the ruleCtrl.manageRule method even further by not sending in res as a parameter but by returning the result from db.getRule instead. Let router.post('/verify) handle req and res, so to make it even easier to read.

Upvotes: 2

Related Questions