最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Asyncawait in Nodejs + Mongoose - Stack Overflow

programmeradmin4浏览0评论

I'm new to Promises and async/await programming and I am not sure I am getting it straight. I am creating an API in Nodejs, with Express, Mongoose and MongoDB. I have seen a lot of tutorials on how to deal with asynchronicity but all of them are about NodeJs projects where the routing and the DB query are in the same file. example:

const asyncMiddleware = fn =>
  (req, res, next) => {
    Promise.resolve(fn(req, res, next))
      .catch(next);
};

router.get('/users/:id', asyncMiddleware(async (req, res, next) => {
    const something = await getSomethingFromDb({ id: req.params.id })
    res.json(something);
}));

However, for clarity purposes, I have separated the routing from the controller but I have serious doubts I have done it correctly. Here is my code:

router.js

const asyncMiddleware = fn =>
  (req, res, next) => {
    Promise.resolve(fn(req, res, next))
      .catch(next);
};

router.get('/something/:id', asyncMiddleware(async (req, res, next) => {
    const answer = await somethingController.findById(req, res, next)
}));

controller.js

exports.findById = async (req, res, next) => {
    const something = await Something.findById(req.params.id).exec();
    res.send(something);
};

I have tried to console.log() stuff to check what gets printed what, but I have realized, due to the awaiting part, this whole piece of code will wait for the query to finish. Is this well implemented? How can I test it?

Versions: NodeJs v10.16.3 Mongoose v5.7.1

I'm new to Promises and async/await programming and I am not sure I am getting it straight. I am creating an API in Nodejs, with Express, Mongoose and MongoDB. I have seen a lot of tutorials on how to deal with asynchronicity but all of them are about NodeJs projects where the routing and the DB query are in the same file. example:

const asyncMiddleware = fn =>
  (req, res, next) => {
    Promise.resolve(fn(req, res, next))
      .catch(next);
};

router.get('/users/:id', asyncMiddleware(async (req, res, next) => {
    const something = await getSomethingFromDb({ id: req.params.id })
    res.json(something);
}));

However, for clarity purposes, I have separated the routing from the controller but I have serious doubts I have done it correctly. Here is my code:

router.js

const asyncMiddleware = fn =>
  (req, res, next) => {
    Promise.resolve(fn(req, res, next))
      .catch(next);
};

router.get('/something/:id', asyncMiddleware(async (req, res, next) => {
    const answer = await somethingController.findById(req, res, next)
}));

controller.js

exports.findById = async (req, res, next) => {
    const something = await Something.findById(req.params.id).exec();
    res.send(something);
};

I have tried to console.log() stuff to check what gets printed what, but I have realized, due to the awaiting part, this whole piece of code will wait for the query to finish. Is this well implemented? How can I test it?

Versions: NodeJs v10.16.3 Mongoose v5.7.1

Share Improve this question asked Oct 1, 2019 at 17:03 chopedschopeds 3171 gold badge6 silver badges23 bronze badges 2
  • You could (and maybe should) simplify this to just router.get('/something/:id', asyncMiddleware(somethingController.findById)); – Bergi Commented Oct 1, 2019 at 17:34
  • Is it handled as an async function if I do it that way? I thought I always had to specify asynchronous functions at the beginning @Bergi – chopeds Commented Oct 1, 2019 at 18:27
Add a ment  | 

2 Answers 2

Reset to default 14

Firstly you don't need an "asyncMiddleware". Let me give a full example of how you can separate routes and controllers, while keeping the controller async:

Controller

exports.findById = async (req, res, next) => {
    try{
       const something = await Something.findById(req.params.id).exec();
        return res.send(something);
    }catch(err){
       return res.status(500).send({
        message: err.message
      })
    }   
};

You should wrap you async calls in a try/catch block.

Route

You would then simply call your controller in your route like so:

router.get('/:id', Controller.findByID)

and that's it. You don't need any additional async call on your route.

If you have middlewares your want to add you route you can do it like this:

//for single middleware
router.get('/:id',somethingMiddle,Controller.findByID)

//for multiple middleware
router.get('/:id',[somethingMiddle, anotherMiddle],Controller.findByID)

Let me know if this helps

Personally, I would stick to using try-catch for my async functions, rather than using a middleware. This could look something like the following:

module.exports.view = async function(req, res, next) {
  try {
    var something = await Something.findById(req.params.id).orFail();
    res.send(something);
  } catch (err) {
    next(err);
  }
};

Then in your router it would simply be:

router.get('/something/:id', somethingController.view);

Doing this way will allow you to manipulate and handle special error cases for that controller action, before next(err) sends it to the global error handler.

Now I'm not sure if this is something you're expecting or not, but you may want to call .orFail() on your query. This way an error is thrown if the "something" with the specified ID is not found. Otherwise the something variable will be null. But that totally depends on how you want your API to function.

Additionally, when you define an async function, it is basically saying that the function returns a Promise. An await statement basically tells the program to pause the function until the promise is resolved. In this example, await will wait for the database to return the result before continuing the controller action. Express will magically handle awaiting your async route methods and middleware.

发布评论

评论列表(0)

  1. 暂无评论