Home > database >  nodejs : multer - req.file is undefined when using upload.single() in a middleware
nodejs : multer - req.file is undefined when using upload.single() in a middleware

Time:10-23

hello I am trying to create a custom middle-ware for file upload with multer with customization (allowed file type, destination folder ...). the upload is working but the req.file is always undefined, below you can find my code edit : I have changed the code images to code snippets to make it easier to copy thank you

// route
router.patch('/profile-picture',
    [
        AsyncErrorWrapper(passport.verifyJwt()),
        AsyncErrorWrapper(singleFileUpload('/images/', ['image/png', 'image/jpeg'])),
    ], AsyncErrorWrapper(userController.updateProfilePicture))

// singleFileUpload
const {uploadConfiguration, multerDelay} = require("../services/multer.service")

/**
 * 
 * @param {*} dest destination folder inside the /tmp
 * @param {*} whitelist list of extensions which are allowed to be uploaded
 * @returns 
 */
module.exports = (dest, whitelist, name = 'file') => {
    return async (req, res, next) => {
        // get the upload config obj
        const upload = uploadConfiguration(dest, whitelist)

        // call the upload.single
        upload.single(name)(req, res, next)

        // make sur we wait for the upload to finish to solve the req.file is undefined
        await multerDelay()
        next()
    }
}

// service
const uploadConfiguration = (dest, whitelist) => {
    // storage 
    const storage = multer.diskStorage({
        destination: (req, file, cb) => {
            // set the directory 
            const dir = `${tmpStorage}${dest}`
            mkdirp.sync(dir)
            cb(null, dir)
        },
        filename: (req, file, cb) => {
            cb(null, Date.now()   path.extname(file.originalname));
        },

    })

    // upload filter
    const uploadFilter = (req, file, cb) => {

        if (!whitelist.includes(file.mimetype)) {
            return cb(new AppError('file type is not allowed', 400), false)
        }
        // make this to solve problem with req.file is undefined in the following middleware
        req.file = file
        cb(null, true)
    }

    return multer({
        storage: storage,
        fileFilter: uploadFilter
    })
}

/**
 * 
 * @returns promise that resolve after the queue is clear
 */
const multerDelay = () => {
    console.log('multerDelay');
    return new Promise((resolve) => setTimeout(() => resolve(), 0))
} 
    // controller 
    const updateProfilePicture = async (req, res, next) => {
    
        console.log(req.file) // undefined
        return res.status(200).json({msg: 'hi'})
    
    }

CodePudding user response:

The issue is, you can't run a middleware like that

When you do

upload.single(name)(req, res, next)

You are passing next to the function to run it internally

Running next more than once will always cause errors

You should split it into two functions

// singleFileUpload
module.exports = (dest, whitelist, name = 'file') => {
    return async (req, res, next) => {
        // get the upload config obj
        const upload = uploadConfiguration(dest, whitelist)

        // call the upload.single
        upload.single(name)(req, res, next)
    }
}
// waitForDelay
module.exports = (dest, whitelist, name = 'file') => {
    return async (req, res, next) => {
        // make sur we wait for the upload to finish to solve the req.file is undefined
        await multerDelay()
        next()
    }
}
router.patch('/profile-picture',
    [
        AsyncErrorWrapper(passport.verifyJwt()),
        AsyncErrorWrapper(singleFileUpload('/images/', ['image/png', 'image/jpeg'])),
        AsyncErrorWrapper(waitForDelay()),
    ], AsyncErrorWrapper(userController.updateProfilePicture))

^ untested code

  • Related