I'm setting up my first RESTful API with Express & Mongo DB. So far i've been trying to come up with a pattern that if I don't work on the project for a while I can easily pick up again and same goes if someone new were to join the project.
The basic idea is when someone hits an endpoint, if that endpoint requires amends to 1 or more Mongo DB documents then i'll go ahead and fetch that document in Mongo DB and store it in res.locals to be actioned later on in another middleware. This is shown in exports.populateUserById:
exports.populateUserById = async (req,res,next) => {
const user = await User.findById(req.body.userId);
res.locals.userToAction = user;
next();
}
I will then make my amend to that Mongo DB document in a separate middleware like so and reference the res.locals from the previous middleware which I can call .save() on no problem.:
exports.addToTeam = async (req, res, next) => {
res.locals.userToAction.team = req.body.teamId;
await res.locals.userToAction.save();
res.locals.responseData = { success: true }
next();
}
Finally I go to my last middleware which is shared by all endpoints which just sends the res.JSON:
exports.respond = (req,res) => {
res.json(res.locals.responseData);
}
My full endpoint would look like this in my routes:
router.post('/add-user-to-team',
authController.populateUserById,
authController.addToTeam,
authController.respond
);
I have found this method to be handy because I can call the populateUserById controller function on many different endpoints then in another controller function edit the document how I need to.
Is this a fairly typical/ acceptable pattern for a restful API with Mongo DB/ Express or am I on the wrong path?
Also worth mentioning. obviously there are more controller functions in between that check for valid MongoDB object id's and catch async errors but have left them out of this example.
Thanks!
/add-user-to-team, I would expect it to be/team/:teamId/user/:userIdoruser/:userId/team/:teamId/. Also, why do you break up each mongoose operation? Instead why not just nest the operations and pass all the objects you need in the response at the very end (i.e.userToActionandresponseData) ?