Multer: Validations before upload

Created on 13 Jul 2015  路  9Comments  路  Source: expressjs/multer

Hello guys,

I'm trying to submit a multipart form data to a nodejs server, and I'd like to check if all required fields exist in the form, before the upload starts.

However, multer only finish the form parsing after the upload is complete.

Anyone know how I can check the form fields before the upload? I'm not interested in uploading files first, and only then check if the other form data is valid.

Thanks guys!

Most helpful comment

This might actually be quite a challenge since the browser is free to (and often does, see below) send files and fields mixed and in any order. This means that multer can't read the fields first, and then decide if it should continue with the files or bail on the stream.

However, there is a "workaround" if you really need it. If you construct a FormData object with javascript on the client, you could potentially let the browser know in which order you want it to send things. Now, as fair as I know, the spec dosen't say that the browser should send things in the same order that you .append() them, but it seems to be working for now.

The second part now is to somehow instruct multer to discontinue if there is a problem with the fields. I'm pretty sure that it's currently possible with all the hooks that we expose. But we are working on minimizing that in #131. I don't think it's that interesting if it's possible or not, but wether there is a clear path of expressing this intent or not.

With the new code, I actually think that there is. You could use the fileFilter feature to express that "only accept files if valid fields has preceded it". Something like this:

let multer = require('multer')

function hasRequiredFields (fields) {
  // 1. Implement this!
}

let upload = multer({
  fileFilter: function (req, file, cb) {
    cb(null, hasRequiredFields(req.body))
  }
})

app.post('/upload', upload, function (req, res) {
  // 2. Handle the request
})

// 3. ????
// 4. PROFIT!!

All 9 comments

This might actually be quite a challenge since the browser is free to (and often does, see below) send files and fields mixed and in any order. This means that multer can't read the fields first, and then decide if it should continue with the files or bail on the stream.

However, there is a "workaround" if you really need it. If you construct a FormData object with javascript on the client, you could potentially let the browser know in which order you want it to send things. Now, as fair as I know, the spec dosen't say that the browser should send things in the same order that you .append() them, but it seems to be working for now.

The second part now is to somehow instruct multer to discontinue if there is a problem with the fields. I'm pretty sure that it's currently possible with all the hooks that we expose. But we are working on minimizing that in #131. I don't think it's that interesting if it's possible or not, but wether there is a clear path of expressing this intent or not.

With the new code, I actually think that there is. You could use the fileFilter feature to express that "only accept files if valid fields has preceded it". Something like this:

let multer = require('multer')

function hasRequiredFields (fields) {
  // 1. Implement this!
}

let upload = multer({
  fileFilter: function (req, file, cb) {
    cb(null, hasRequiredFields(req.body))
  }
})

app.post('/upload', upload, function (req, res) {
  // 2. Handle the request
})

// 3. ????
// 4. PROFIT!!

Multer 1.0.0 is now released and you should be able to use the workaround suggested above.

Unfortunately there is nothing we can do about the order in which the browsers send things.

Hi @LinusU , As you said above.

app.post('/upload', upload, function (req, res) {
  // 2. Handle the request
})

the "upload" looks like a router middleware, and the router middleware required to be a function. But the "update" is an object In fact.

the source code as follow.

function multer (options) {
  if (options === undefined) {
    return new Multer({})
  }

  if (typeof options === 'object' && options !== null) {
    return new Multer(options)
  }

  throw new TypeError('Expected object for argument options')
}

SO, I got an error.

 Error: Route.post() requires callback functions but got a [object Object]

Yeah I posted the workaround before 1.0 was released so it didn't account for that syntax.

You need to change it into one of the new functions for accepting files, e.g. upload.single('avatar'). Which one you should choose depends on what files you want to accept, check the documentation for more information.

Is there any work around besides the one above ? @LinusU
I want to use my Joi middleware but if the multer middleware comes before it then req.body is undefined meaning that its not being parsed.

For example:

router.post('/savings/', idValidaiton.validateIdKey, validCompany,parser.single('imageUrl'), 
createSavings )

The above wont work but the below works:

router.post('/savings/', parser.single('imageUrl'),idValidaiton.validateIdKey, validCompany, 
createSavings )

So basically the image is uploaded before the req.body is validate

My parse Middleware looks like this:

const multer = require('multer')
const cloudinary = require('cloudinary')
const cloudinaryStorage = require('multer-storage-cloudinary')

cloudinary.config({
cloud_name: process.env.CLOUD_NAME,
api_key: process.env.CLOUD_API_KEY,
api_secret: process.env.CLOUD_API_SECRET
})

 const storage = cloudinaryStorage({
 cloudinary: cloudinary,
 folder: 'ratehogs',
 allowedFormats: ['jpg', 'png', 'jpeg'],
 transformation: [{ width: 500, height: 500, crop: 'limit' }]
 })

 const parser = multer({ storage: storage })

 module.exports = parser

Trying to see how i can incorporate you solution

This might actually be quite a challenge since the browser is free to (and often does, see below) send files and fields mixed and in any order. This means that multer can't read the fields first, and then decide if it should continue with the files or bail on the stream.

However, there is a "workaround" if you really need it. If you construct a FormData object with javascript on the client, you could potentially let the browser know in which order you want it to send things. Now, as fair as I know, the spec dosen't say that the browser should send things in the same order that you .append() them, but it seems to be working for now.

The second part now is to somehow instruct multer to discontinue if there is a problem with the fields. I'm pretty sure that it's currently possible with all the hooks that we expose. But we are working on minimizing that in #131. I don't think it's that interesting if it's possible or not, but wether there is a clear path of expressing this intent or not.

With the new code, I actually think that there is. You could use the fileFilter feature to express that "only accept files if valid fields has preceded it". Something like this:

let multer = require('multer')

function hasRequiredFields (fields) {
  // 1. Implement this!
}

let upload = multer({
  fileFilter: function (req, file, cb) {
    cb(null, hasRequiredFields(req.body))
  }
})

app.post('/upload', upload, function (req, res) {
  // 2. Handle the request
})

// 3. ????
// 4. PROFIT!!

What if I don't attach file at all? Then this fileFilter won't be fired meaning req without file will be forwarded next

Will test it out and advise

Will test it out and advise

u were able to make that work?

suggestion: what about sending a request to validate only text fields first and if validation passes, then you send another request with the validated data and the file you want to upload

Was this page helpful?
0 / 5 - 0 ratings

Related issues

thammarith picture thammarith  路  3Comments

samipjain picture samipjain  路  4Comments

bpetty-formfast picture bpetty-formfast  路  3Comments

BlueOctober picture BlueOctober  路  3Comments

ChristianRich picture ChristianRich  路  4Comments