I am using Bookshelf.js
to handle a user registration API end-point, designed with NodeJS and ExpressJS. But upon POSTing to the register url, I keep hitting an error at one of the User model functions.
Here is routes/index.js
var User = require(./models/User);
router.post('/register', function(req, res, next){
if(!req.body.username || !req.body.password){
return res.status(400).json({message: 'Please fill out all fields'});
}
try {
var hash = User.createPassword(req.body.password);
console.log(hash);
new User({email: req.body.username, name: req.body.username, password: hash}).save().then(function(model) {
return res.json({token: this.generateJWT()});
});
} catch (ex) {console.log(ex.stack);}
});
Here is models/Users.js
var jwt = require('jsonwebtoken');
var bcrypt = require('bcrypt');
var bookshelf = require('../config/bookshelf');
var User = bookshelf.Model.extend({
tableName: 'users',
constructor: function() {
bookshelf.Model.apply(this, arguments);
this.on('saving', function(model, attrs, options) {
console.log(this.createPassword(model.attributes.password));
});
},
createPassword: function(password) {
bcrypt.genSalt(10, function (err, salt) {
if(err) return next(err);
bcrypt.hash(password, salt, function (err, hash) {
if(err) return next(err);
return hash;
});
});
},
validPassword: function(password, encryptedPass) {
bcrypt.compare(password, user.encryptedPass, function (err, match) {
if(err) cb(err);
return (match) ? true : false;
});
},
generateJWT: function() {
// set expiration to 60 days
var today = new Date();
var exp = new Date(today);
exp.setDate(today.getDate() + 60);
return jwt.sign({
_id: this._id,
email: this.email,
exp: parseInt(exp.getTime() / 1000),
}, 'SECRET');
}
});
module.exports = User;
When I try to POST to register, I get the following stack trace:
TypeError: undefined is not a function
at \routes\index.js:185:21
at Layer.handle [as handle_request] (\node_modules\express\lib\router\layer.js:95:5)
at next (\node_modules\express\lib\router\route.js:131:13)
at Route.dispatch (\node_modules\express\lib\router\route.js:112:3)
at Layer.handle [as handle_request] (\node_modules\express\lib\router\layer.js:95:5)
...
In the stack trace, \routes\index.js:185:21 is the following line: var hash = User.createPassword(req.body.password);
at createPassword
.
So what am I doing wrong here? Why is it failing to recognize the createPassword
function?
User
is a constructor but the method is defined on its prototype. You have to create an instance to call a method on. TryNote that from the look of your method, it's probably better as a static method (it doesn't access this), which the other answer describes how to create.
createPassword()
is not defined as a static method (a.k.a.classProperties
), but you are calling it as such. Try this model definition. It should exposecreatePassword()
directly on the User class as a static method.Extra: You'll need to fix your createPassword, as it's async. Below I've converted it to a Promise-returning function (as bookshelf uses promises extensively) and show an example usage for your route handler