NodeJS Best Practices: Errors for Flow Control?

In Node.js, should errors be used to control flow, or should they be used more as exceptions?

I am writing an authentication controller and some unit tests in Sails.js, and currently my login method checks if a user with the same username exists. If the user already exists with the username, my model method calls its callback arguments with a new Error object, for example:

Model:

exists: function (options, cb) { User.findOne({ where: { username: typeof options === 'Object' && options.username ? options.username : options }, }).exec(function (err, user) { if (err) return cb(err); if (user) return cb(new Error("A user with that username already exists.")); cb(null, !!user); }); }, 

Controller:

 User.exists(req.body.user.username, function (err, exists) { if (err) { console.log("error: ", err); return res.status(409).json({ message: err }); } User.create(req.user).then(function (data) { res.status(201).json({ user: data }); }); }); 

Is this the best practice? I'm not sure that node conventions make mistakes for exceptional cases or for flow control. I think I should rewrite this, but I want to know the agreements before I do this. I seem to have seen some examples written this way in Sails. Thanks!

+5
source share
2 answers

The above answer is good for Express, but in Sails controllers you shouldn't call next ; Best practice is always to return an answer. In most Sails code examples, you won't even see next as an argument to a controller action function. Also note that Sails comes with some default response methods built right into the res object, such as res.serverError and res.badRequest , as well as res.negotiate , which will try to direct the error to the appropriate handler for you based on the status code. Thus, your example can be configured as follows:

Model:

 exists: function (options, cb) { User.findOne({ where: { username: typeof options === 'Object' && options.username ? options.username : options }, }).exec(function (err, user) { // res.negotiate will default to a 500 server error if (err) return cb(err); // res.negotiate will just output the status code and error object // as JSON for codes between 400 and 500, unless you // provide a custom view as api/responses/badRequest.ejs if (user) return cb({ status: 409, message: "A user with that username already exists." }); cb(null, !!user); }); }, 

Controller:

 User.exists(req.body.user.username, function (err, exists) { // Let Sails handle those errors for you if (err) {return res.negotiate(err);} User.create(req.user).then(function (data) { res.status(201).json({ user: data }); }); }); 
+2
source

Node (or Javascript really) can throw errors in exceptions using the throw keyword:

 if (something_went_wrong) { throw new Error('Doh!'); } 

You can also add additional parameters to the Error object by default to give more semantic meaning to your errors in your program. With this in mind, you will not want to throw an error in your route handler, because this will cause the process and your server to crash.

When using route handlers in Sails (or really really), you should certainly check the type of error and respond to the client accordingly.

 // -- Route handler app.get('/something', function (req, res, next) { DB.create({ username: 'user' }, function (err, docs) { if (err) { // This checks to see if we have a unique error from MongoDB // and send the appropriate response to the client if (err.code === 11000 || error.code === 11001) { return res.send(409); // or return res.json(409, {message: "User exists"}); } // Any other error type is assumed to be an internal error so we pass it // down the chain to the error handler middleware return next(err); } // This is a client error, not an internal error so we respond to the client // with the appropriate client error type if (docs.length === 0) return res.send(404); if (user.notAuthorized) return res.send(403); res.send('All Good'); }); }); 

Please note that in the case when the database responds with an internal error, we move on to the next() function, which is picked up by intermediate error-handling software in a chain. Any middleware with arrival 4 is defined as middleware for error handling. Sails probably have some default error handler, but you can probably also override it - you will need to check the relevant documents for this information, since I prefer which control I get using only Express.

+2
source

Source: https://habr.com/ru/post/1208678/


All Articles