So, I am building a small app in order to learn how to use express.js. I have a really simple form, submitting one text field and a file simultaneously. This is submitted through FormData, so I'm using multer on the back end to process the request. What I would like to do is perform a validation on the form's text input BEFORE taking any action concerning the file (i.e. save only if the validation succeeds, if not send some kind of error message). I used to do it that way
<form id="form" method='POST' enctype='multipart/form-data'>
<input type='file' id='file-upload' name='file-upload' />
<input type='text' id='text-upload' name='text-upload' />
<input type='submit' />
</form>
Back end : router.js
//somewhere in the router file
import {importedController} from './controllers/importedController';
/* some other routes */
router.post('/upload', importedController.processfunction);
importedController.js
exports.processfunction = (req, res, next) => {
var getFields = multer().any();
getFields(req, res, err => {
if (err) {return next(err);}
req.checkBody('text-upload','must not be empty!').notEmpty();
//do the validation from here
var errors = req.validationErrors();
if (errors) {
//some logic
} else {
//some other stuff
//in both, i can access req.body and req.file to do whatever i want
}
});
}
I noticed however that there seems to be a new syntax for express validator, so I tried to follow this syntax and to do:
router.js
router.post('/upload', [ body('text-input', 'must be not empty').not().isEmpty()], importedController.processfunction);
but then in my importedController.js, the validation doesnt work outside of the multer getFields() function that I defined (seems logical since the request hasn't been processed yet). Yet, if I try to include it inside the multer function:
importedController.js
exports.processfunction = (req, res, next) => {
var getFields = multer().any();
getFields(req, res, err => {
if (err) {return next(err);}
errors = validationResult(req);
if (!errors.isEmpty()) {
//actually always yields and error...
} else { //stuff}
});
}
Then it always returns an error, although the field entry is correct. It is as if the validation was performed on the 'non processed' req, where req.body is empty. Although the code works now so there is no hurry, I would like to follow the new syntax for the sake of later projects. Any help greatly appreciated !
EDIT: A solution I found thanks to @gustavohenke's answer below
Realized that down to the core, my issue was linked to way the multer module works, since it seems to upload the file before it processes the form data (which must come before the validation) -- at least the multer module seems to give you no control on when it uploads the file, giving you no ability to call another middleware before actually saving it.
So what I ended up doing was using ajax on the client side to first send the form data only (saving the file for later), into a multer().any()
middleware chained with the form validator logic. Depending on the response given by that first call to the server, I then chain it with another ajax to finally upload the file to another route, this time using a multer(storage: myStorage).single('myFileInputName')
to upload the file.
Thinking about it, this solution seems perhaps better than what I thought about doing at first: not only does it avoid saving the file in case of bad form input, it even avoids using any bandwidth to send the file (that can be decently heavy) if the input is incorrect.
You're correct when you say that the validation took place before the body was processed by multer.
In both cases, the validators are run as soon as possible; but please note the following differences:
req.body
is still empty.