Validate models with mongoose nodejs

0

I have my user model.

// models/user.js
var mongoose=require("mongoose");
var Schema=mongoose.Schema;
var userSchema=new Schema({
    name:{
        type:String,
        required:"Es necesario un nombre",
        maxlength:[10,"Nombre muy largo max 10"]
    },
    lastName:{
        type:String,
        required:"Es necesario el apellido",
        maxlength:[10,"Apellido muy largo"]
    },
    userName:{
        type:String,
        unique:true,
        require:"Es necesario un username",
    },
    password:{
        type:String,
        require:"Es necesario un password",
        validate:{
            validator:function(pass){
                    if( this.password_confirmation!=undefined)
                        return this.password_confirmation==pass;
                    else{
                        return true;
                    }
            },
            message:"Las contraseñas son diferentes"
        }
    },
    email:{
    type:String,
    require:"Es necesario un email"
    }
})

userSchema.virtual("password_confirmation").get(function(){
    return this.p_c
}).set(function(password){
    this.p_c=password;
})

var User=mongoose.model("User",userSchema);
module.exports=User;

An endpoint to log me in.

//  routes/user.js
router.route("/login").get(login.login_get).post(login.login_post);

// login_post

var login_post=function(req,res,next){

    if(!req.body.password || !req.body.userName){
        res.send("Error");
    }

    User.findOne({userName:req.body.userName,password:req.body.password},function(err,us){
        if(err)console.log(String(err));
        console.log("Usuario encontra",us);
        res.send(us);
    });

}

What I want to do is the following, validate from the model before entering User.findOne, for example something like that.

var user=new User(req.body,function(err){
   if(err)res.send("Error",String(err));
});

User.findOne({userName:user.userName,password:user.password},function(err,us){
        if(err)console.log(String(err));
        console.log("Usuario encontra",us);
        res.send(us);
    });

to avoid using this and validate from the model.

  if(!req.body.password || !req.body.userName){
            res.send("Error");
        }

or else you can like that maybe something like that.

    var validate=function(model,next){
    if(//NO SE QUE IRIA PARA VALIDAR EL MODELO//){}
    next("//Algo como los errores del modelo model.err//);    
    }   

   var user=new User(req.body);
   validate(user,function(err){
       if(err){
            console.log(String(err));
            res.send("Hubo un error validando los datos",err);
        }
}

}

This is to be able to search for users, since to create it is not necessary to do something extra, because if I throw out the errors that I have put.

Since when doing

User.findOne({userName:req.body.userName,password:req.body.password},function(err,us){
        if(err)console.log(String(err));
        console.log("Usuario encontra",us);
        res.send(us);
    });

without the validation it throws only that it did not find the user, and no error if for example I do not put password.

For md

I did not know about DTO, as soon as you validate it looks good, then if I should create a DTO schema in specific cases, but what I was doing is the following, what I was doing in my examples was to bring the error pull , which defined in the model because for example if you put something like

User.create(req.body,function(err,us){
if(err) console.log(String(err)); 
console.log(us);
});

This does bring me the set of errors, for example if passwords do not match, or fill a field, I wanted to do something for the findOne, but this does not bring me the error pull (defined in userSchema) to show them in a toast, but rather does not detect any error therefore does not return anything.

With what you set me to create a DTO I could do it, but the question is that I wanted to minimize the code I put, in addition to the libraries, so my query.

If the response codes went away, I still need to optimize the code better.

    
asked by Kevin AB 24.09.2016 в 17:46
source

1 answer

1
  

What I want to do is the following, validate from the model before entering User.findOne, for example something like that.

     

var user=new User(req.body,function(err){ if(err)res.send("Error",String(err)); });

Here is an important difference: Normally the object / model that you transport over the network is different from the one you store in the base. For example, you would never send the user's password when you answer for security reasons, nor will you allow it to change some properties of the registry, such as an id that relates it to another entity, etc.

We usually call the objects that we store in the base as the MODEL, and the objects that we use to transfer data between nodes, the DTO (or Data Transfer Object).

Now, in Javascript for its dynamism, it is not always necessary to create a separate model (the primary model will not work because it requires name, lastName, etc). You have to evaluate it in each case. This case does not seem necessary, as it is two fields and easy to validate.

Alternatively, a lighter option than creating a Schema for UserDTO would be to use some lightweight schema validation libraries like indicative .

p>

By the way, in the code that you showed us there is nothing for when the user does not exist in the base or the key does not match (maybe it was a simplified example, but I have taken it into account in the example)

Another change that I recommend you make is to use the appropriate response codes osea 500, 401 and 400 depending on the case (see in the code)

const indicative = require('indicative')

const userLoginDTOschema = {
  userName: 'required',
  password: 'required'
}

var login_post = function(req, res, next) {
  indicative.validate(req.body, userLoginDTOschema)
    .then(function() {
      // validation passed
      User.findOne({
          userName: req.body.userName,
          password: req.body.password
        },
        function(err, us) {
          if (err) {
            console.log(String(err));
            // en viejas versiones es send(500)
            res.sendStatus(500); // Internal Server Error
          }
          if (us) { 
            console.log("Usuario encontrado", us);
            res.send(us); // Ojo!!! aqui te faltaria filtrar el password y demas datos sensibles.
          } else {
            console.log("Usuario no encontrado", us);
            res.sendStatus(401); // Unauthorized
          }
        });
    }).catch(function(errors) {
      // validation failed
      res.sendStatus(400); // Bad Request
    })
}

Salu2

EDITION:

I understand what you say in your edition: Maybe the example of LOGIN is not the best case because you never want to report the exact error, for security reasons. But since this is applicable to any entity I tell you that indicative has another method

var errores = indicative.validateAll(data, rules)

Which returns an array with the list of errors / violations of the given schema. For what you use to inform.

It's your choice, I understand that adding another library is a complicated decision for many reasons, and this is just an alternative.

To my liking it is a good alternative to your general problem, it allows you to do all kinds of validations, customize error messages, use templates and argue error messages, it allows you to sanitize (aka sanitize) the input data and the documentation is based on examples and you can read it in 15-20 minutes.

    
answered by 24.09.2016 / 20:28
source