How to do avoid huge nested if else - javascript

This is my code for logging in
method: 'POST',
path: '/api/login/sp',
config: { auth: false },
handler: function (request, reply) {
User.findOne({ phone: request.payload.phone }, function (err, user) {
if (err) throw err;
if (user !== null) {
user.comparePassword(request.payload.password, function (err, isMatch) {
if (err) throw err;
if (isMatch) { // Login success
data = {
"statusCode": 200,
"token": generateJWT(user._id)
}
return reply(data);
}
else {
reply(Boom.unauthorized('Invalid Account'))
}
});
}
else { // Invalid User
reply(Boom.unauthorized('Invalid Account'))
}
});
}
It takes a lot of code and makes it very hard to read. Is there a way to better write this part of the code so that it is easily maintainable and readable?

You may use return reply():
User.findOne({phone: request.payload.phone}, function (err, user) {
if (err) throw err;
if (user === null) return reply(Boom.unauthorized('Invalid Account'));
user.comparePassword(request.payload.password, function (err, isMatch) {
if (err) throw err;
if (!isMatch) return reply(Boom.unauthorized('Invalid Account'));
data = {
"statusCode": 200,
"token": generateJWT(user._id)
};
return reply(data);
});
})

Try using the return early pattern: Return early pattern for functions
User.findOne(..., {
// generic error
if (err) throw err;
// invalid user
if (user === null) {
reply(Boom.unauthorized('Invalid Account'));
return;
}
user.comparePassword(..., {
if (err) throw err;
if (!isMatch) {
reply(Boom.unauthorized('Invalid Account'));
return;
}
data = {
"statusCode": 200,
"token": generateJWT(user._id)
};
reply(data);
});
});

Related

How to store value to var from another function

I'm comparing my two documents named: user and bloodrequest based on their id, if they match then display the values in the table bloodrequest that has the same id. My problem here is that I'm trying to store the current logged in user to a var like this : var permit = mainUser.branch_id then used a $where statement using this: this.chapter_id == permit but gives me error.
MongoError: TypeError: mainUser is undefined :
Here is my code, My only problem is how to pass mainUser.branch_id to var permit, I'm just starting to learn
router.get('/bloodapprovedrequestmanagement', function(req, res) {
User.find({}, function(err, users) {
if (err) throw err;
User.findOne({ username: req.decoded.username }, function(err, mainUser) {
if (err) throw err;
if (!mainUser) {
res.json({ success: false, message: 'No user found' });
} if (mainUser.branch_id === '111') {
Bloodrequest.find({$where: function(err) {
var permit = mainUser.branch_id//gives me error here
return (this.request_status == "approved" && this.chapter_id == permit) }}, function(err, bloodrequests) {
if (err) throw err;
Bloodrequest.findOne({ patient_name: req.decoded.patient_name }, function(err, mainUser) {
if (err) throw err;
res.json({ success: true, bloodrequests: bloodrequests });
});
});
}
});
});
});
Declare the variable outside the local scope.
`router.get('/bloodapprovedrequestmanagement', function(req, res) {
var permit;
User.find({}, function(err, users) {
if (err) throw err;
User.findOne({ username: req.decoded.username }, function(err, mainUser) {
if (err) throw err;
if (!mainUser) {
res.json({ success: false, message: 'No user found' });
}
if(mainUser.branch_id === '111') {
permit = mainUser.branch_id;
Bloodrequest.find({$where: function(err) {
return (this.request_status == "approved" && this.chapter_id == permit) }}, function(err, bloodrequests) {
if (err) throw err;
Bloodrequest.findOne({ patient_name: req.decoded.patient_name }, function(err, mainUser) {
if (err) throw err;
res.json({ success: true, bloodrequests: bloodrequests });
});
});
}
});
});
});`
Convert your callback to async await that more simple.
router.get('/bloodapprovedrequestmanagement', function async(req, res) {
try {
var permit;
let mainUser = await User.findOne({ username: req.decoded.username });
if(mainUser && mainUser.branch_id && mainUser.branch_id === '111') {
permit = mainUser.branch_id;
// here you add your condiion for (this.request_status == "approved" && this.chapter_id == permit).
let bloodRequestData = await Bloodrequest.findOne({ patient_name: req.decoded.patient_name });
res.json({ success: true, bloodrequests: bloodRequestData });
}
} catch (error) {
throw error
}
}
As per my understanding you have not used User.find({}) and Bloodrequest.find({}) data in your code.

mysqljs-mysql transaction is too verbose. Simpler alternative?

Here is a snippet of transaction with node-mysql from the official github repo:
connection.beginTransaction(function(err) {
if (err) { throw err; }
connection.query('INSERT INTO posts SET title=?', title, function (error, results, fields) {
if (error) {
return connection.rollback(function() {
throw error;
});
}
var log = 'Post ' + results.insertId + ' added';
connection.query('INSERT INTO log SET data=?', log, function (error, results, fields) {
if (error) {
return connection.rollback(function() {
throw error;
});
}
connection.commit(function(err) {
if (err) {
return connection.rollback(function() {
throw err;
});
}
console.log('success!');
});
});
});
});
I feel there are too much boilerplates over here. Isn't there a more succinct way of making a transaction, like this?:
/* invalid code */
connection.beginTransaction();
const q1 = connection.query("SELECT 1;");
const q2 = connection.query("SELECT 2;");
const q3 = connection.query("SELECT 3;");
if (q1 && q2 && q3) {
connection.commit();
else {
connection.rollback();
}
It would be synchronous in this case though.

Express router callbacks

I'm a little new to Express/Node.js/Mongoose and I've ran into callback hell. What I'm trying to do is get a request in to this API URL /page/module/add/:id, if successful call buildMod(data), then that function calls getMod(data), and then that function calls writeMod(data) and eventually I want to pass the true value right back up to my router.
Once I have the response, I want to return it. I've searched online and there's not many similar situations--I personally think I've got myself in too deep...
router.get('/page/module/add/:id', function(req, res) {
Client.find({"emailAddress": emailAddress, "sequence.slug": pageSlug},
{"emailAddress": 1, "sequence.$": 1}, function (err, data) {
if (!err) {
res.statusCode = 200;
buildMod(data);
return res.json(data);
} else {
res.statusCode = 500;
log.error('Internal error(%d): %s', res.statusCode, err.message);
return res.json({
error: 'Server error'
});
}
}).select('sequence emailAddress domain');
});
function buildMod(data) {
getMod(data);
}
function getMod(data) {
Module.find({ 'module_id': moduleNumID }, function (err, module) {
if(!module) {
return false;
}
if (!err) {
writeMod(data);
} else {
return false;
}
});
}
function writeMod(data) {
fs.appendFile(location, content, function(err) {
if (err) throw err;
return true;
});
}
I know the declarations are wrong for the functions for callbacks but I've been trying and I just can't seem to get past this stage. I'm sure this is definitely possible, any help is really appreciated!
fs.appendFile is asynchronous and you can not return from asynchronous calls.
Make use of callback
router.get('/page/module/add/:id', function(req, res) {
Client.find({
"emailAddress": emailAddress,
"sequence.slug": pageSlug
}, {
"emailAddress": 1,
"sequence.$": 1
}, function(err, data) {
if (!err) {
res.statusCode = 200;
buildMod(data, function(data) {
res.json(data);
});
} else {
res.statusCode = 500;
log.error('Internal error(%d): %s', res.statusCode, err.message);
return res.json({
error: 'Server error'
});
}
}).select('sequence emailAddress domain');
});
function buildMod(data, cb) {
getMod(data, cb);
}
function getMod(data, cb) {
writeMod(data, cb);
}
function writeMod(data, cb) {
fs.appendFile(location, content, function(err) {
if (err) throw err;
cb(true);
});
}

Callback/Promises implementation for a boolean check

Currently I have the following callback system:
var saveTask = function(err, result) {
if (err) return callback(err, result);
var newid = mongoose.Types.ObjectId();
var task = new Task({
_id: newid,
taskname: req.body.name,
teamid: req.body.team,
content: req.body.content,
creator: req.user.userId
});
task.save(function (err) {
if (!err) {
log.info("New task created with id: %s", task._id);
return callback(null, task);
} else {
if(err.name === 'ValidationError') {
return callback('400', 'Validation error');
} else {
return callback('500', 'Server error');
}
log.error('Internal error(%d): %s', res.statusCode, err.message);
}
});
};
if (req.body.team) {
valTeam.isMember(req.body.team, req.user._id, function (err, done) {
if (err) {
saveTask('403', 'Not the owner or member of this team');
} else {
saveTask(null, true);
}
});
} else {
saveTask(null, true);
}
valTeam.isMember
exports.isMember = function(teamid, userid, callback) {
Team.find({'_id':teamid, $or:[{'creator': userid }, {'userlist': { $in : [userid]}}]}, function(err, result) {
if (err) return err;
console.log(result);
if (!result.length)
return callback('404', false);
else
return callback(null, true);
});
}
In short, if team is sent by POST, I'm checking if the user is member of that ID in valTeam.isMember. Am I using the correct syntax and best method to call back my saveTask function to save the task if the user is part of the team?
This code currently works, but I feel like there should be an easier way to do it? How could I use a promise to achieve the same thing?
Thanks in advance.
It's curious the fact that you create objects instead Schemas. However "every head is a different world", this is my way:
task.save(function(error, data){
if (error) {
trow error;
} else {
//Make whatever you want here with data
});

No access to this from within nested callback

I have the following code:
var Company = function(app) {
this.crypto = require('ezcrypto').Crypto;
var Company = require('../models/company.js');
this.company = new Company(app);
}
// Create the company
Company.prototype.create = function (name, contact, email, password, callback) {
this.hashPassword(password, function(err, result) {
if (err) throw err;
console.log(this.company); // Undefined
this.company.create(name, contact, email, result.password, function(err, result) {
if (err) {
return callback(err);
}
return callback(null, result);
});
});
}
// Get company with just their email address
Company.prototype.hashPassword = function (password, callback) {
if(typeof password !== 'string') {
var err = 'Not a string.'
} else {
var result = {
password: this.crypto.SHA256(password)
};
}
if (err) {
return callback(err);
}
return callback(null, result);
}
module.exports = Company;
The problem is that this.company is undefined on line 11 of that code block.
I know this is not what I think, but I'm not sure how to refactor to get access to the correct this.
so theres 2 solution's to this
first the dirty one
Company.prototype.create = function (name, contact, email, password, callback) {
var that = this; // just capture this in the clojure <-
this.hashPassword(password, function(err, result) {
if (err) throw err;
console.log(that.company); // Undefined
that.company.create(name, contact, email, result.password, function(err, result) {
if (err) {
return callback(err);
}
return callback(null, result);
});
});
}
and the clean one using bind https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/bind
Company.prototype.create = function (name, contact, email, password, callback) {
this.hashPassword(password, (function(err, result) {
if (err) throw err;
console.log(this.company); // Undefined
this.company.create(name, contact, email, result.password, function(err, result) {
if (err) {
return callback(err);
}
return callback(null, result);
});
}).bind(this));
}
You can reference this through another variable by declaring it in the Company.create scope, like this:
// Create the company
Company.prototype.create = function (name, contact, email, password, callback) {
var me = this;
this.hashPassword(password, function(err, result) {
if (err) throw err;
console.log(me.company); // Undefined - not anymore
me.company.create(name, contact, email, result.password, function(err, result) {
if (err) {
return callback(err);
}
return callback(null, result);
});
});
}
Untested, but it should work like this.

Categories