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?
Multer accepts an options object with the following keys:
dest
or storage
- Where to store the filesfileFilter
- Function to control which files are acceptedlimits
- Limits of the uploaded datapreservePath
- Keep the full path of files instead of just the base nameRef: https://www.npmjs.com/package/multer#multeropts
So, to initialize the object correctly, it should be:
module.exports = {
pictureMdw: multer({ storage: pictureStorage, fileFilter: pictureFileFilter }),
}