express-validator giving undefined value when form set to enctype='multipart/form-data'

Viewed 2471

So I am making this login auth app using basic node.js+express. So when I am taking the values(name, email, etc) from the register page, I am validating the values using express-validator. But, I am getting every value undefined(name, email, etc) when the register page form has enctype='multipart/form-data'. But when I am removing enctype='multipart/form-data', the values are coming just fine!!

So any solution for this? I am just a beginner in Node.js.

(P.S. I need enctype='multipart/form-data' because I am uploading a profileimage while on registration)

(P.S In the code I have removed the middlewares to show the minimal codes for just register.jade and its routes)

I have successfully registered without using enctype='multipart/form-data', but here I can't upload the image.

(P.S. Using multer for file upload)

./app.js

var createError = require('http-errors');
var express = require('express');
var path = require('path');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var logger = require('morgan');
var expressValidator = require('express-validator');
var session = require("express-session");
var passport = require("passport");
var localStratergy = require("passport-local").Strategy;
var multer = require("multer");
var upload = multer({dest: './uploads'});
var flash = require("connect-flash");
var bcrypt = require("bcryptjs");
var moongo = require("mongodb");
var mongoose = require("mongoose");
var db = mongoose.connection;

var indexRouter = require('./routes/index');
var usersRouter = require('./routes/users');
const { check, validationResult } = require('express-validator');
var app = express();

app.use('/', indexRouter);
app.use('/users', usersRouter);


module.exports = app;

./routes/user.js

var express = require('express');
var router = express.Router();
var multer = require("multer");
var bodyParser = require('body-parser');
var passport = require("passport");
var LocalStrategy = require("passport-local").Strategy;
var User = require('../models/user');

router.use(bodyParser.json());
router.use(bodyParser.urlencoded({ extended: false }));
var upload = multer({dest: './uploads'});
const {check, validationResult} = require('express-validator');
/* GET users listing. */
router.get('/', function(req, res, next) {
  res.send('respond with a resource');
});

router.get('/register', function(req, res, next) {
  res.render('register', {title: 'Register'});
});

router.post('/register', [
  check('name' , 'Name Field is required').not().isEmpty(),
  check('email', 'Email Field is required').not().isEmpty(),
  check('email', 'Email Field is not valid').isEmail(),
  check('username', 'Username Field is required').not().isEmpty(),
  check('password', 'Password Field is required').not().isEmpty(),
  check('password2', 'Passwords do not match').custom(
    (value, {req, loc, path}) => {
      if( value != req.body.password) {
        throw new error("Passwords do not match");
      } else{
        return value;
      }
    })

], upload.single('profileimage'),function(req, res, next) {

  var name = req.body.name;
  var email = req.body.email;
  var username = req.body.username;
  var password = req.body.password;
  var password2 = req.body.password2;
  if(req.file){
    console.log("Uploading");
    var profileimage = req.file.filename;
  } else{
    console.log("No File Selected");
    var profileimage = "noimage.jpg";
  }
  const errors = validationResult(req);
  if(!errors.isEmpty()){
    res.render('register', {
      error: errors.array()
    })
  } else{
    var newUser = new User({
      name: name,
      email: email,
      username: username,
      password: password,
      profileimage: profileimage
    });

    User.createUser(newUser, function(err, user){
      if(err) throw err;
      console.log(user);
    });
    req.flash('success', 'You have now registered');

    res.location('/');
    res.redirect('/');  
  }

});


module.exports = router;

./views/register.jade

extends layout

block content
    h2.page-header Register
    p Please Register Below   
    if error
        each errors, i in error
            div.alert.alert-danger    #{errors.msg}
    form(action="/users/register", method="post" enctype='multipart/form-data')
        .form-group
            label Name
            input.form-control(name="name", type="text", placeholder="Enter Name", class="name")

        .form-group
            label Email
            input.form-control(name="email", type="email", placeholder="Enter Email")

        .form-group
            label Username
            input.form-control(name="username", type="text", placeholder="Enter Username")

        .form-group
            label Password
            input.form-control(name="password", type="password", placeholder="Enter password")
        .form-group
            label Retype Password
            input.form-control(name="password2", type="password", placeholder="Enter password again")

        .form-group
            label Profile Image
            input.form-control(name="profileimage", type="File")

        input.btn.btn-primary(type="submit", name="submit", value="Register")

I expect that I do include enctype='multipart/form-data' for my image upload and that the rest of values does not get set to undefined, because then my express-validator is not working

2 Answers

Your use of 'multipart/form-data' prevents Express from parsing the values of the other form fields. The easiest way to get around this is to use a middleware that parses multipart forms, and gives you access to both fields and image/s.

There are several such middleware packages, each with its own support/documentation/track record: multer, busboy, multiparty etc. I've used multiparty in several projects in the past, with no issues, but there are newer packages.

I resolve the problem modifying the order (in the Router) of the middlewares: first must go Multer, and then Express-Validator. (I think this is because Multer added fields to the req.body, so: first you must add those fields, and then, do the verifications.

In this way, it works, becouse multer goes first:

router.post('/register',multerUploadUser.single('user_photo'), verificationRegister,  userController.registerUpload);

In this way, doesn´t:

router.post('/register', verificationRegister, multerUploadUser.single('user_photo'),  userController.registerUpload);
Related