Refactor passport local strategy using promisy. Problem with .catch()











up vote
0
down vote

favorite












In an express + passport + local strategy app, I use bcrypt to hash password, this is working:



var bcrypt = require('bcrypt-nodejs');

familySchema.pre('save', function(next) {
var family = this;
var SALT_FACTOR = 14;

if (!family.isModified('password')) return next();

bcrypt.genSalt(SALT_FACTOR, function(err, salt) {
if (err) return next(err);

bcrypt.hash(family.password, salt, null, function(err, hash) {
if (err) return next(err);
family.password = hash;
next();
});
});
});


Then I refactored using promisify and async/await:



const bcrypt = require('bcrypt-nodejs');
const util = require('util');
const bcryptGenSalt = util.promisify(bcrypt.genSalt);
const bcryptHash = util.promisify(bcrypt.hash);

familySchema.pre('save', async function(next) {
var family = this;
const SALT_FACTOR = 14;
if (!family.isModified('password')) return next();
const salt = await bcryptGenSalt(SALT_FACTOR).catch(next);
const hash = await bcryptHash(family.password, salt, null).catch(next);
family.password = hash;
next();
});



  • Is this refactoring actually correct?

  • How can I double check that errors in bcryptGenSalt or bcryptHash are caught correctly? Is there a way to somehow "force" bcryptGenSalt into throwing an error, for testing?


  • Next step, how can I remove the two .catch(next), using a wrapAsync util function:



wrapAsync.js:



module.exports = fn => (req, res, next) => fn(req, res, next).catch(next);


Following attempt is not working, error: family.isModified() is not a function, (probably because the this is not right anymore).
And what to do with the arguments of wrapAsync, as next should be the 3rd argument?



familySchema.pre(
'save',
wrapAsync(async function(req, res, next) {
var family = this;
const SALT_FACTOR = 14;
debugger;
if (!family.isModified('password')) return next();
const salt = await bcryptGenSalt(SALT_FACTOR);
const hash = await bcryptHash(family.password, salt, null);
family.password = hash;
next();
})
);









share|improve this question
























  • I just realized that I'm using bcrypt-nodejs package instead of official bcrypt! And bcrypt support promises. As per bcrypt documentation ( github.com/kelektiv/node.bcrypt.js#with-promises ), bcrypt will automatically output a promise if no callback function is provided. So I can remove the promisify part.
    – xiaoju
    Nov 9 at 9:50

















up vote
0
down vote

favorite












In an express + passport + local strategy app, I use bcrypt to hash password, this is working:



var bcrypt = require('bcrypt-nodejs');

familySchema.pre('save', function(next) {
var family = this;
var SALT_FACTOR = 14;

if (!family.isModified('password')) return next();

bcrypt.genSalt(SALT_FACTOR, function(err, salt) {
if (err) return next(err);

bcrypt.hash(family.password, salt, null, function(err, hash) {
if (err) return next(err);
family.password = hash;
next();
});
});
});


Then I refactored using promisify and async/await:



const bcrypt = require('bcrypt-nodejs');
const util = require('util');
const bcryptGenSalt = util.promisify(bcrypt.genSalt);
const bcryptHash = util.promisify(bcrypt.hash);

familySchema.pre('save', async function(next) {
var family = this;
const SALT_FACTOR = 14;
if (!family.isModified('password')) return next();
const salt = await bcryptGenSalt(SALT_FACTOR).catch(next);
const hash = await bcryptHash(family.password, salt, null).catch(next);
family.password = hash;
next();
});



  • Is this refactoring actually correct?

  • How can I double check that errors in bcryptGenSalt or bcryptHash are caught correctly? Is there a way to somehow "force" bcryptGenSalt into throwing an error, for testing?


  • Next step, how can I remove the two .catch(next), using a wrapAsync util function:



wrapAsync.js:



module.exports = fn => (req, res, next) => fn(req, res, next).catch(next);


Following attempt is not working, error: family.isModified() is not a function, (probably because the this is not right anymore).
And what to do with the arguments of wrapAsync, as next should be the 3rd argument?



familySchema.pre(
'save',
wrapAsync(async function(req, res, next) {
var family = this;
const SALT_FACTOR = 14;
debugger;
if (!family.isModified('password')) return next();
const salt = await bcryptGenSalt(SALT_FACTOR);
const hash = await bcryptHash(family.password, salt, null);
family.password = hash;
next();
})
);









share|improve this question
























  • I just realized that I'm using bcrypt-nodejs package instead of official bcrypt! And bcrypt support promises. As per bcrypt documentation ( github.com/kelektiv/node.bcrypt.js#with-promises ), bcrypt will automatically output a promise if no callback function is provided. So I can remove the promisify part.
    – xiaoju
    Nov 9 at 9:50















up vote
0
down vote

favorite









up vote
0
down vote

favorite











In an express + passport + local strategy app, I use bcrypt to hash password, this is working:



var bcrypt = require('bcrypt-nodejs');

familySchema.pre('save', function(next) {
var family = this;
var SALT_FACTOR = 14;

if (!family.isModified('password')) return next();

bcrypt.genSalt(SALT_FACTOR, function(err, salt) {
if (err) return next(err);

bcrypt.hash(family.password, salt, null, function(err, hash) {
if (err) return next(err);
family.password = hash;
next();
});
});
});


Then I refactored using promisify and async/await:



const bcrypt = require('bcrypt-nodejs');
const util = require('util');
const bcryptGenSalt = util.promisify(bcrypt.genSalt);
const bcryptHash = util.promisify(bcrypt.hash);

familySchema.pre('save', async function(next) {
var family = this;
const SALT_FACTOR = 14;
if (!family.isModified('password')) return next();
const salt = await bcryptGenSalt(SALT_FACTOR).catch(next);
const hash = await bcryptHash(family.password, salt, null).catch(next);
family.password = hash;
next();
});



  • Is this refactoring actually correct?

  • How can I double check that errors in bcryptGenSalt or bcryptHash are caught correctly? Is there a way to somehow "force" bcryptGenSalt into throwing an error, for testing?


  • Next step, how can I remove the two .catch(next), using a wrapAsync util function:



wrapAsync.js:



module.exports = fn => (req, res, next) => fn(req, res, next).catch(next);


Following attempt is not working, error: family.isModified() is not a function, (probably because the this is not right anymore).
And what to do with the arguments of wrapAsync, as next should be the 3rd argument?



familySchema.pre(
'save',
wrapAsync(async function(req, res, next) {
var family = this;
const SALT_FACTOR = 14;
debugger;
if (!family.isModified('password')) return next();
const salt = await bcryptGenSalt(SALT_FACTOR);
const hash = await bcryptHash(family.password, salt, null);
family.password = hash;
next();
})
);









share|improve this question















In an express + passport + local strategy app, I use bcrypt to hash password, this is working:



var bcrypt = require('bcrypt-nodejs');

familySchema.pre('save', function(next) {
var family = this;
var SALT_FACTOR = 14;

if (!family.isModified('password')) return next();

bcrypt.genSalt(SALT_FACTOR, function(err, salt) {
if (err) return next(err);

bcrypt.hash(family.password, salt, null, function(err, hash) {
if (err) return next(err);
family.password = hash;
next();
});
});
});


Then I refactored using promisify and async/await:



const bcrypt = require('bcrypt-nodejs');
const util = require('util');
const bcryptGenSalt = util.promisify(bcrypt.genSalt);
const bcryptHash = util.promisify(bcrypt.hash);

familySchema.pre('save', async function(next) {
var family = this;
const SALT_FACTOR = 14;
if (!family.isModified('password')) return next();
const salt = await bcryptGenSalt(SALT_FACTOR).catch(next);
const hash = await bcryptHash(family.password, salt, null).catch(next);
family.password = hash;
next();
});



  • Is this refactoring actually correct?

  • How can I double check that errors in bcryptGenSalt or bcryptHash are caught correctly? Is there a way to somehow "force" bcryptGenSalt into throwing an error, for testing?


  • Next step, how can I remove the two .catch(next), using a wrapAsync util function:



wrapAsync.js:



module.exports = fn => (req, res, next) => fn(req, res, next).catch(next);


Following attempt is not working, error: family.isModified() is not a function, (probably because the this is not right anymore).
And what to do with the arguments of wrapAsync, as next should be the 3rd argument?



familySchema.pre(
'save',
wrapAsync(async function(req, res, next) {
var family = this;
const SALT_FACTOR = 14;
debugger;
if (!family.isModified('password')) return next();
const salt = await bcryptGenSalt(SALT_FACTOR);
const hash = await bcryptHash(family.password, salt, null);
family.password = hash;
next();
})
);






express error-handling promise this






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Nov 8 at 14:04

























asked Nov 8 at 13:50









xiaoju

526




526












  • I just realized that I'm using bcrypt-nodejs package instead of official bcrypt! And bcrypt support promises. As per bcrypt documentation ( github.com/kelektiv/node.bcrypt.js#with-promises ), bcrypt will automatically output a promise if no callback function is provided. So I can remove the promisify part.
    – xiaoju
    Nov 9 at 9:50




















  • I just realized that I'm using bcrypt-nodejs package instead of official bcrypt! And bcrypt support promises. As per bcrypt documentation ( github.com/kelektiv/node.bcrypt.js#with-promises ), bcrypt will automatically output a promise if no callback function is provided. So I can remove the promisify part.
    – xiaoju
    Nov 9 at 9:50


















I just realized that I'm using bcrypt-nodejs package instead of official bcrypt! And bcrypt support promises. As per bcrypt documentation ( github.com/kelektiv/node.bcrypt.js#with-promises ), bcrypt will automatically output a promise if no callback function is provided. So I can remove the promisify part.
– xiaoju
Nov 9 at 9:50






I just realized that I'm using bcrypt-nodejs package instead of official bcrypt! And bcrypt support promises. As per bcrypt documentation ( github.com/kelektiv/node.bcrypt.js#with-promises ), bcrypt will automatically output a promise if no callback function is provided. So I can remove the promisify part.
– xiaoju
Nov 9 at 9:50














1 Answer
1






active

oldest

votes

















up vote
2
down vote



accepted










The refactoring is not correct, because after the .catch statements, the rest of the function will continue to run. So if for instance bcryptGenSalt throws an error, next is called (because of .catch(next)) but it will also continue with the next line of code, until the end of the function (where next is called again).



Typically, in async functions, you use try/catch around statements that may throw errors:



familySchema.pre('save', async function(next) {
const SALT_FACTOR = 14;
if (!this.isModified('password')) return next();
try {
const salt = await bcryptGenSalt(SALT_FACTOR);
const hash = await bcryptHash(this.password, salt, null);
this.password = hash;
return next();
} catch(err) {
return next(err);
}
});



Is there a way to somehow "force" bcryptGenSalt into throwing an error, for testing?




It depends on which tools you use for testing, but there are packages like sinon that can stub existing functions so you can controllably make then throw errors, which you can then test for.






share|improve this answer





















  • "because after the .catch statements, the rest of the function will continue to run" --> Does this mean that the pattern described in thecodebarbarian.com/80-20-guide-to-express-error-handling should be avoided? In short, they use a wrapAsync() function to automatically add a .catch(next) to async function calls.
    – xiaoju
    Nov 9 at 14:26













Your Answer






StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");

StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});

function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});


}
});














draft saved

draft discarded


















StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53209106%2frefactor-passport-local-strategy-using-promisy-problem-with-catch%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown

























1 Answer
1






active

oldest

votes








1 Answer
1






active

oldest

votes









active

oldest

votes






active

oldest

votes








up vote
2
down vote



accepted










The refactoring is not correct, because after the .catch statements, the rest of the function will continue to run. So if for instance bcryptGenSalt throws an error, next is called (because of .catch(next)) but it will also continue with the next line of code, until the end of the function (where next is called again).



Typically, in async functions, you use try/catch around statements that may throw errors:



familySchema.pre('save', async function(next) {
const SALT_FACTOR = 14;
if (!this.isModified('password')) return next();
try {
const salt = await bcryptGenSalt(SALT_FACTOR);
const hash = await bcryptHash(this.password, salt, null);
this.password = hash;
return next();
} catch(err) {
return next(err);
}
});



Is there a way to somehow "force" bcryptGenSalt into throwing an error, for testing?




It depends on which tools you use for testing, but there are packages like sinon that can stub existing functions so you can controllably make then throw errors, which you can then test for.






share|improve this answer





















  • "because after the .catch statements, the rest of the function will continue to run" --> Does this mean that the pattern described in thecodebarbarian.com/80-20-guide-to-express-error-handling should be avoided? In short, they use a wrapAsync() function to automatically add a .catch(next) to async function calls.
    – xiaoju
    Nov 9 at 14:26

















up vote
2
down vote



accepted










The refactoring is not correct, because after the .catch statements, the rest of the function will continue to run. So if for instance bcryptGenSalt throws an error, next is called (because of .catch(next)) but it will also continue with the next line of code, until the end of the function (where next is called again).



Typically, in async functions, you use try/catch around statements that may throw errors:



familySchema.pre('save', async function(next) {
const SALT_FACTOR = 14;
if (!this.isModified('password')) return next();
try {
const salt = await bcryptGenSalt(SALT_FACTOR);
const hash = await bcryptHash(this.password, salt, null);
this.password = hash;
return next();
} catch(err) {
return next(err);
}
});



Is there a way to somehow "force" bcryptGenSalt into throwing an error, for testing?




It depends on which tools you use for testing, but there are packages like sinon that can stub existing functions so you can controllably make then throw errors, which you can then test for.






share|improve this answer





















  • "because after the .catch statements, the rest of the function will continue to run" --> Does this mean that the pattern described in thecodebarbarian.com/80-20-guide-to-express-error-handling should be avoided? In short, they use a wrapAsync() function to automatically add a .catch(next) to async function calls.
    – xiaoju
    Nov 9 at 14:26















up vote
2
down vote



accepted







up vote
2
down vote



accepted






The refactoring is not correct, because after the .catch statements, the rest of the function will continue to run. So if for instance bcryptGenSalt throws an error, next is called (because of .catch(next)) but it will also continue with the next line of code, until the end of the function (where next is called again).



Typically, in async functions, you use try/catch around statements that may throw errors:



familySchema.pre('save', async function(next) {
const SALT_FACTOR = 14;
if (!this.isModified('password')) return next();
try {
const salt = await bcryptGenSalt(SALT_FACTOR);
const hash = await bcryptHash(this.password, salt, null);
this.password = hash;
return next();
} catch(err) {
return next(err);
}
});



Is there a way to somehow "force" bcryptGenSalt into throwing an error, for testing?




It depends on which tools you use for testing, but there are packages like sinon that can stub existing functions so you can controllably make then throw errors, which you can then test for.






share|improve this answer












The refactoring is not correct, because after the .catch statements, the rest of the function will continue to run. So if for instance bcryptGenSalt throws an error, next is called (because of .catch(next)) but it will also continue with the next line of code, until the end of the function (where next is called again).



Typically, in async functions, you use try/catch around statements that may throw errors:



familySchema.pre('save', async function(next) {
const SALT_FACTOR = 14;
if (!this.isModified('password')) return next();
try {
const salt = await bcryptGenSalt(SALT_FACTOR);
const hash = await bcryptHash(this.password, salt, null);
this.password = hash;
return next();
} catch(err) {
return next(err);
}
});



Is there a way to somehow "force" bcryptGenSalt into throwing an error, for testing?




It depends on which tools you use for testing, but there are packages like sinon that can stub existing functions so you can controllably make then throw errors, which you can then test for.







share|improve this answer












share|improve this answer



share|improve this answer










answered Nov 8 at 14:22









robertklep

133k17231240




133k17231240












  • "because after the .catch statements, the rest of the function will continue to run" --> Does this mean that the pattern described in thecodebarbarian.com/80-20-guide-to-express-error-handling should be avoided? In short, they use a wrapAsync() function to automatically add a .catch(next) to async function calls.
    – xiaoju
    Nov 9 at 14:26




















  • "because after the .catch statements, the rest of the function will continue to run" --> Does this mean that the pattern described in thecodebarbarian.com/80-20-guide-to-express-error-handling should be avoided? In short, they use a wrapAsync() function to automatically add a .catch(next) to async function calls.
    – xiaoju
    Nov 9 at 14:26


















"because after the .catch statements, the rest of the function will continue to run" --> Does this mean that the pattern described in thecodebarbarian.com/80-20-guide-to-express-error-handling should be avoided? In short, they use a wrapAsync() function to automatically add a .catch(next) to async function calls.
– xiaoju
Nov 9 at 14:26






"because after the .catch statements, the rest of the function will continue to run" --> Does this mean that the pattern described in thecodebarbarian.com/80-20-guide-to-express-error-handling should be avoided? In short, they use a wrapAsync() function to automatically add a .catch(next) to async function calls.
– xiaoju
Nov 9 at 14:26




















draft saved

draft discarded




















































Thanks for contributing an answer to Stack Overflow!


  • Please be sure to answer the question. Provide details and share your research!

But avoid



  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.


To learn more, see our tips on writing great answers.





Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


Please pay close attention to the following guidance:


  • Please be sure to answer the question. Provide details and share your research!

But avoid



  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.


To learn more, see our tips on writing great answers.




draft saved


draft discarded














StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53209106%2frefactor-passport-local-strategy-using-promisy-problem-with-catch%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown





















































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown

































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown







這個網誌中的熱門文章

Academy of Television Arts & Sciences

L'Équipe

1995 France bombings