Search code examples
javascriptnode.jsexpressmulter

fileFilter optinon in multer causing request.file to be undefined


I want Multer allows just photo to be uploaded but it doesn't work and gives request.file = undefined and at the same time the file.mimetype = image/jpeg which is correct

Here is a clip from Postman: enter image description here

I checked the headers also and it contains Content-Type = multipart/form-data; boundary=<calculated when request is sent>

then I tried and removed fileFilter: multerFilter configurations from Multer and the surprise that everything worked fine without any single problem. Here is the related code:

const multerStorage = multer.memoryStorage();

// 2) Creating a multer filter (to test if the uploaded file is really an image):
const multerFilter = (request, file, cb) => {
  if (file.mimetype.startsWith("image")) cb(null, true);
  cb(new AppError(400, `The only accepted files are images, please select an image ${request.file} file tyep: ${file.mimetype}`), false);
};

const upload = multer({ storage: multerStorage, fileFilter: multerFilter });

exports.updateMyPhoto = upload.single("photo");

Please help me find what's wrong with my fileFilter configuration

UPDATE:

I switched between the two conditions inside multerFilter and the program is working perfectly now. the new code:

const multerFilter = (request, file, cb) => {
  if (!file.mimetype.startsWith("image")) cb(new AppError(400, `The only accepted files are images, please select an image ${request.file} file tyep: ${file.mimetype}`), false);
  cb(null, true);
  };

I still don't know the reason for this behaviour so I'd appreciate your help


Solution

  • You should call your callback function cb with return keyword. Otherwise after the first callback function call, your code will continute and eventually the second callback function will be called and this will cause this confusing problem to be occur. To solve this update your code using return keyword:

    const multerFilter = (request, file, cb) => {
      if (file.mimetype.startsWith("image")) return cb(null, true);
      return cb(new AppError(400, `The only accepted files are images, please select an image ${request.file} file tyep: ${file.mimetype}`), false);
    };
    

    To understand how your current implementation behaves, run the following code snippet and see the outputs.

    const filterCheckWithoutReturnKeyword = (number, callback) => {
      if(number > 10) callback('Number is greater than 10!');
      callback('Number is less than 10!');
    };
    
    const filterCheckWithReturnKeyword = (number, callback) => {
      if(number > 10) return callback('Number is greater than 10!');
      return callback('Number is less than 10!');
    };
    
    const callbackFn = (message) => console.log(message);
    
    filterCheckWithoutReturnKeyword(5, callbackFn);
    filterCheckWithoutReturnKeyword(15, callbackFn);
    
    // Seperator log
    console.log('---------------');
    
    filterCheckWithReturnKeyword(5, callbackFn);
    filterCheckWithReturnKeyword(15, callbackFn);