javascriptnode.jsexpressmulter

Multer destination configuration not being applied


I'm trying to enable a profile pic feature in my web application. To do so, I'm using Express (4.19.2) for the server and Multer (1.4.5-lts.1) for multipart requests and file handling, however, Multer destination code seems to be ignored. I've followed some examples and landed the following Multer middleware code:

// Required modules
const fs = require('fs');
const path = require('path');
const multer = require('multer');

const validPictureExtensions = ['jpg', 'jpeg', 'png'];

// Profile picture configuration
const pictureStorage = multer.diskStorage({
    destination: (req, file, cb) => {
        // First check if resources directory exists
        if (!fs.existsSync(path.join(__dirname, '..', '..', 'resources'))) {
            console.info('Resources directory created.');
            fs.mkdirSync(path.join(__dirname, '..', '..', 'resources'));
        }
        
        // Then check if users directory exists
        if (!fs.existsSync(path.join(__dirname, '..', '..', 'resources', 'users'))) {
            console.info('Users directory created.');
            fs.mkdirSync(path.join(__dirname, '..', '..', 'resources', 'users'));
        }

        cb(null, 'users');
    },
    filename: (req, file, cb) => {
        const ext = file.originalname.split('.').pop();
        const name = `${req.user.id}.${ext}`;
        cb(null, name);
    }
});

const pictureFileFilter = (req, file, cb) => {
    const ext = file.originalname.split('.').pop();
    const isValid = validPictureExtensions.includes(ext);
    cb(null, isValid);
};

module.exports = {
    pictureMdw: multer({ pictureStorage, pictureFileFilter }),
}

Then, I'm using the previous middleware in a /users route, looking like this:

// Router
const router = require('express').Router();

// Middleware
const { pictureMdw } = require('./../middlewares/fileUpload');

// PUT
router.put('/:tagOrID/picture', pictureMdw.single('file'), userCont.updateUserPicture);

module.exports = router;

The relevant controller code after Multer middleware is executed is the following

await sharp(req.file.buffer)
                .resize({ width: 500, height: 500 })
                .jpeg()
                .toFile(path.join(__dirname, '..', '..', 'resources', 'users', `${tag}.jpeg`));

            res.sendStatus(200);

Everything works fine only if the necessary directories are previously created with something like mkdir -p resources/users, otherwise, I get an error. I'm yet to run a debugger but not even console.log('Here') gets printed when called inside the middleware configuration. What could be happening here? Should I check for directory existence in the controller instead? Should I opt for a completely different approach instead?


Solution

  • Multer accepts an options object with the following keys:

    Ref: https://www.npmjs.com/package/multer#multeropts

    So, to initialize the object correctly, it should be:

    module.exports = {
        pictureMdw: multer({ storage: pictureStorage, fileFilter: pictureFileFilter }),
    }