Search code examples
javascriptexpresses6-promise

How to make an express route do 2 things before sending back a response to the client?


I'm trying to accomplish various things within an express route, in short I have this route /checkNsguid where I submit a form. I would like the route to do the following:

  1. verify if the nguid code is a valid one (it exists in the db).
  2. if it finds a valid nguid code it copies some fields from the NGUID table to the ModelTable (it updates the model object)
  3. it sends back to the client application the udpated model object.

For some reason I'm still getting back the old model obj. I can see that it is updated on the db with the valid fields, but res.send(...) still sends me the old obj.

I don't know if it's the way I'm using Promises , using next() or something else I'm missing. If someone could point me on the right direction pls ?

Thanks

/**
 * Check if nguidCode is in the list
 *
 * @return {JSON}
 */
router.post(
  '/checkNguid',
  (req, res, next) => {
    let modelID = req.body.modelID
    let nguid = req.body.nguid

    // 1. Step 1
    // Goes to the CheckNGUID table
    // maps through all the collections until it finds one that matches 
    // the  submitted nguidcode
    // verifies that the code is valid and if so then copies various 
    // fields to the ModelTable via `.updateInfosFromOldDb`

    // After that I don't want anything else to do with that response obj.
    // I want to "pass" control to Step 2 

    nguidCode
      .checkNguid(nguid)
      .then((response) => {
        console.log('this is the response inside backend', response)

        response.length === 0
          ? res.status(400).json({ result: 'nok', error: 'Invalid nguidCode' })
          : response.map((el) =>
            // [NOTE]: Updates the model object with the nguid info if found
              modelModel.updateInfosFromOldDb(
                modelID,
                nguid,
                el.rate,
                el.subscribedAt,
              ),
            )
          next()


        // console.log('this is the response inside backend 2', response)
        // res.status(200).json({ result: 'ok', model: response })
        // res.status(200).json({ result: 'ok', model: response })
      })
      .catch((error) => {
        res.status(400).json({ result: 'nok', Error: error.toString() })
      })
  },

  // 2. Step 2
  // This is the updated model obj I would like to send back to the client app.

  // [ASK]: I want to send back the updated model Object,
  // However I'm still getting back the old one.
  (req, res) => {
    modelModel.getByID(req.body.modelID).then((response) => {
      console.log('response inside the next()', response)
      res.status(200).json({ result: 'ok', model: response })
    })
  },
)

updateInfosFromOldDb

const updateInfosFromOldDb = (modelID, nguid, rate, subscribedAt) => {

  return new Promise((resolve, reject) => {
    ModelModel.findOne({ id: modelID }, (err, model) => {
      if (err) {
        reject(err);
      }
      model.nguidCode= nguid
      model.rate= rate
      model.subscribedAt =subscribedAt
      //model.payments.push(paymentId);

      model.save((err, response) => {
        if (err) {
          reject(err)
        } else {
          resolve(response)
        }
      })
    })
    
  });

}

Solution

  • You are getting old response because next() being called before nguidCode.checkNguid promise resolves i.e. before your database call completes. In order to fix this issue, we need to move next() within then() block -

    /**
     * Check if nguidCode is in the list
     *
     * @return {JSON}
     */
    router.post(
      '/checkNguid',
      (req, res, next) => {
        let modelID = req.body.modelID
        let nguid = req.body.nguid
    
        // console.log(req.body, 'req.body in the backend')
    
        nguidCode
          .checkNguid(nguid)
          .then((response) => {
            console.log('this is the response inside backend', response)
            if(response.length === 0) {
              throw new Error('Invalid nguidCode');
            } else {
              // Wrapping list of promises in Promise.all so that then() callback is invoked once all
              // promises are resolved
              return Promise.all(response.map((el) =>
              // [NOTE]: Updates the model object with the nguid info if found
                modelModel.updateInfosFromOldDb(
                  modelID,
                  nguid,
                  el.rate,
                  el.subscribedAt,
                ),
              ))
            }
            // console.log('this is the response inside backend 2', response)
            // res.status(200).json({ result: 'ok', model: response })
            // res.status(200).json({ result: 'ok', model: response })
          })
          .then((data) => {
            return next()
          })
          .catch((error) => {
            return res.status(400).json({ result: 'nok', Error: error.toString() })
          })
        // [NOTE]: This also works I go onto the modelModel.getByID(...)
      },
    
      // [ASK]: I want to send back the updated model Object,
      // However I'm still getting back the old one.
      (req, res) => {
        modelModel.getByID(req.body.modelID).then((response) => {
          console.log('response inside the next()', response)
          return res.status(200).json({ result: 'ok', model: response })
        })
      },
    )