Refactoring middleware code of NodeJS project, using routes, controllers and models

百般思念 提交于 2020-05-15 09:25:47

问题


I currently have difficulties to structure my NodeJS project. I followed several YouTube series, seeing people using different techniques to structure their code. Which structure would you suggest me in my case? What's best practice?

I've my app.js which contains connection establishment to MongoDB, initializing express, bodyParser, pug as view engine and finally starting the server.

My router.js contains all routes and unfortunately some middleware code, which I want to move into their own dedicated controller.

The models folder holds all schema files for MongoDB.

// File structure:
.
├─ controllers
|  ├─ morticians.js
|  ├─ people.js
|  └─ pickups.js
├─ models
|  ├─ mortician.js
|  ├─ person.js
|  └─ pickup.js
├─ views
|  ├─ elements
|  |  └─ ..
|  ├─ pages
|  |  ├─ dashboard.pug
|  |  └─ ..
|  └─ layout.pug
├─ app.js
└─ router.js

We're a hospital an sometimes people die here. A mortician comes and picks them up, but the process to remove this person from our systems isn't automated yet. That's what this webapp is for. Pulling all deceased from our database, displaying them in the webapp and removing it as soon as the mortician came and picked that person up.

1. When the main-page is requested, it finds all people, then all morticians from MongoDB and finally rendering the page. I can imagine, that this not best practice, but how to refactor it?

// snippet router.js
const Person= require('./models/person')
const Mortician = require('./models/mortician')
router.get('/', (req, res, next) => {
  Person.find({ pickedUp: false }, (err, people) => {
    Mortician.find({}, (err, morticians) => {
      if (err) return console.log(err);
      res.render('pages/dashboard', {
        title: 'Dashboard',
        persons: people,
        morticians: morticians
      })
    })
  })
}

I tried moving the MongoDB operations into their controller files, like this. It worked, but I'm unsure since it's using multiple promises and not really simplifying things:

// snippet router.js
const ConPeople = require('./controllers/people')
const ConMorticians = require('./controllers/morticians')
router.get('/',
  (req, res, next) => {
    res.locals.options = { pickedUp: false }
    ConPeople.find(req, res, next)
      .then((people) => {
        res.locals.people = people
        next()
      })
  },
  (req, res, next) => {
    res.locals.options = {}
    ConMorticians.find(req, res, next)
      .then((morticians) => {
        res.locals.morticians = morticians
        next()
      })
  },
  (req, res) => {
    res.render('pages/dashboard', {
      title: 'Dashboard',
      people: res.locals.people,
      morticians: res.locals.morticians.reverse()
    })
  }
)

// snippet controllers/people.js
module.exports = {
  find: (req, res, next) => {
    return Person.find(res.locals.options)
  }
}

2. In some cases I need to execute commands like deleting or adding a person from MongoDB. For example, a mortician comes and picks up a person. I need to set the status of that person to pickedUp = true, eventually add a new mortician if that's provided and add a new document to the collection pickups. How do I do that without having to rewrite the same lines?


回答1:


There are 2 things which, when used in combination, will make the code much nicer:

  • Collection.find returns a Promise.
  • To wait for a Promise to resolve in modern Javascript, use await

You can use the following code:

const Person= require('./models/person')
const Mortician = require('./models/mortician')
router.get('/', async (req, res, next) => {
  try {
    const persons = await Person.find({ pickedUp: false });
    const morticians = await Mortician.find({});
    res.render('pages/dashboard', {
      title: 'Dashboard',
      persons,
      morticians,
    });
  } catch(e) {
    // handle errors
  }
});

Or, to retrieve the results in parallel rather than in serial, use Promise.all:

router.get('/', async (req, res, next) => {
  try {
    const [persons, morticians] = await Promise.all([
      Person.find({ pickedUp: false }),
      Mortician.find({})
    ]);
    res.render('pages/dashboard', {
      title: 'Dashboard',
      persons,
      morticians,
    });
  } catch(e) {
    // handle errors
  }
});

You can use the same sort of pattern whenever you have multiple asynchronous calls to make - no need for ugly bracket nesting and indentation.



来源:https://stackoverflow.com/questions/61726347/refactoring-middleware-code-of-nodejs-project-using-routes-controllers-and-mod

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!