-
-
Save stongo/6359042 to your computer and use it in GitHub Desktop.
var mongoose = require('mongoose'); | |
mongoose.connect('mongodb://localhost/test'); | |
var db = mongoose.connection; | |
db.on('error', function() { | |
return console.error.bind(console, 'connection error: '); | |
}); | |
db.once('open', function() { | |
var User; | |
return User = require('./user.js'); | |
}); | |
// Validate a user | |
(function() { | |
var User = require('./user.js'); | |
var me = { username: 'foo' }; | |
var user = new User(me); | |
var err = user.joiValidate(me); | |
if (err) throw err; | |
user.save(function(err, saved) { | |
... | |
}); | |
})(); |
var userSchema = mongoose.Schema({ | |
username: String, | |
password: String, | |
email: String, | |
first_name: String, | |
last_name: String, | |
created: { type: Date, default: Date.now }, | |
}); | |
userSchema.methods.joiValidate = function(obj) { | |
var Joi = require('joi'); | |
var schema = { | |
username: Joi.types.String().min(6).max(30).required(), | |
password: Joi.types.String().min(8).max(30).regex(/[a-zA-Z0-9]{3,30}/).required(), | |
email: Joi.types.String().email().required(), | |
first_name: Joi.types.String().required(), | |
last_name: Joi.types.String().required(), | |
created: Joi.types.Date(), | |
} | |
return Joi.validate(obj, schema); | |
} | |
module.exports = mongoose.model('User', userSchema); |
Good thinking! Good job! Thank you for sharing!
Combination of Joi and Mongoose is great...
userSchema.statics.joiValidate = ...
Could be another choice
Good job! It helped me a lot 👍.
I think it is better to use the validator method before creating a new user schema.
Nice validation for mongoose make my life easier
The problem with this approach is that if you need some fields only for Joi validation, while creating schema mongoose will remove those field. For example in this case, what if there is another field for "repeat password" that is not being saved in db but is required for validation.
If you are using express better method would be to add a middleware for validation so that the problem mentioned by @srujanpurohit doesn't exist. So instead it would look something like this
// user Model
const mongoose = require('mongoose')
const Joi = require('joi')
const userSchema = new mongoose.Schema({
email: {
type: String,
required: [true, 'Please enter a email'],
unique: true,
lowercase: true,
},
password: {
type: String,
required: [true, 'Please enter a password'],
minlength: 8,
},
})
const User = mongoose.model('user', userSchema)
const validateUser = (user) => {
const schema = Joi.object({
email: Joi.string().email().min(5).max(500).required(),
password: Joi.string().min(8).max(1024).required(),
})
return schema.validate(user)
}
module.exports = {
User,
validateUser,
}
// validateMiddleware
module.exports = (validator) => {
return (req, res, next) => {
const { error } = validator(req.body)
console.log('error: ', error)
if (error) {
return res.status(400).send(error.details[0].message)
}
next()
}
}
// authRoute
const { validateUser } = require('../models/User')
const validateMiddleWare = require('../middleware/validate')
const authController = require('../controllers/authController')
router.post('/signup', [validateMiddleWare(validateUser)], authController.signup_post)
If you are using express better method would be to add a middleware for validation so that the problem mentioned by @srujanpurohit doesn't exist. So instead it would look something like this
// user Model const mongoose = require('mongoose') const Joi = require('joi') const userSchema = new mongoose.Schema({ email: { type: String, required: [true, 'Please enter a email'], unique: true, lowercase: true, }, password: { type: String, required: [true, 'Please enter a password'], minlength: 8, }, }) const User = mongoose.model('user', userSchema) const validateUser = (user) => { const schema = Joi.object({ email: Joi.string().email().min(5).max(500).required(), password: Joi.string().min(8).max(1024).required(), }) return schema.validate(user) } module.exports = { User, validateUser, }
// validateMiddleware module.exports = (validator) => { return (req, res, next) => { const { error } = validator(req.body) console.log('error: ', error) if (error) { return res.status(400).send(error.details[0].message) } next() } }
// authRoute const { validateUser } = require('../models/User') const validateMiddleWare = require('../middleware/validate') const authController = require('../controllers/authController') router.post('/signup', [validateMiddleWare(validateUser)], authController.signup_post)
Awesome. Thanks for this. Really helped.
@stongo Great job. Really helpful.
@devChedar I love your approach too
@stongo Great work. You saved me for real.
helpful indeed
Thanks for the write-up @stongo! The example by @devChedar works nicely. However, it gets slightly more complex when you use the same validation for multiple actions with different validation requirements. For example:
- Saving a user requires valid username, email, password
- Logging in as a user requires only email and password
You can make username not required in Joi validation, but since it is actually required for registration, you're then reliant on existence validation getting kicked down the road to the mongoose schema. You can also just not run Joi validation on login requests, but that's also less than ideal.
I suspect the 'best' solution is to create different validation functions for actions with different validation requirements, e.g. validateUserWrite
and validateUserLogin
. At least, that's how I'm going to handle it. Thanks again for the work on putting together a clean way of doing this.
thanks
Thank you, this was helpful.
Thanks broo
thanks this was very helpful 👍
@devChedar I know this is an old thread but just wanted to let you know this helped me out 2 years after you posted👍👍👍
Thanks @stongo, this thread helped me a lot.
Thank you, this was helpful.
@danwhitston Precisely. There's no way around it.
Spend 4 days to understand Joi with Mongoose, even tried Joigoose (it had several limitations) and finally found this. This is very clear. Thank you very much.