Farooq Khan Farooq Khan - 26 days ago 12
Node.js Question

How to upload file using multer or body-parser.

I am a NodeJS beginner, following along a book "Web Development with MongoDB and NodeJS". I am stuck at its chapter 6 with 'multer'. When I use multer for file uploads the server throws the following error:



/Users/fk / Documents / imageuploader / node_modules / express / lib / application.js: 209
throw new TypeError('app.use() requires middleware functions'); ^

TypeError: app.use() requires middleware functions





but when I replace it with bodyParser the server fires up but when I click the upload button it gives me the following error on the browser.



500 TypeError: Cannot read property 'file' of undefined





However, it is supposed to redirect me towards another page, where the uploaded file is shown.

Here is my bodyParser code, please see if I am using it correctly because it gives me "body-parser deprecated" at the starting of the server. I've seen other questions like mine and I followed but none of them really work.



app.use(bodyParser.json());
app.use(bodyParser.urlencoded({
extended: true
}));

app.use(bodyParser({
uploadDir: path.join(__dirname, '../public/upload/temp')
}));





Following code shows how I use multer, just in case if there is something I shouldn't be doing please let me know. Which one would be better in case of uploading files, body-parser or multer?



app.use(multer({
dest: path.join(__dirname, '../public/upload/temp')
}));







var saveImage = function() {
var possible = 'abcdefghijklmnopqrstuvwxyz0123456789',
imgUrl = '';

for (var i = 0; i < 6; i += 1) {
imgUrl += possible.charAt(Math.floor(Math.random() * possible.length));
}

var tempPath = req.files.file.path,
ext = path.extname(req.files.file.name).toLowerCase(),
targetPath = path.resolve('./public/upload/' + imgUrl + ext);

if (ext === '.png' || ext === '.jpg' || ext === '.jpeg' || ext === '.gif') {
fs.rename(tempPath, targetPath, function(err) {
if (err) throw err;
res.redirect('/images/' + imgUrl);
});
} else {
fs.unlink(tempPath, function() {
if (err) throw err;

res.json(500, {
error: 'Only image files are allowed.'
});
});
}
};
saveImage();





Preceding block of code is the logic that I am using to upload the file. In the error it is referring to 'file' as undefined which is in the following line in the saveImage function. It is unable to get the path and therefore throws error 500 according to the else part of the saveImage function. Why is 'file' undefined here? I dont get it.



var tempPath = req.files.file.path,




Answer

multer() returns a middleware generator that uses the settings you specified, so you cannot pass its return value directly to app.use(). You can see all of the types of middleware it can generate in the documentation, but typically the generated middleware are added at the route level instead of globally like the other body parsers. This is because you will typically pass in the name of the file field(s) that you will be expecting.

For example, this will accept a single file (along with any non-file fields) whose form field name is foo:

var upload = multer({
  dest: path.join(__dirname, '../public/upload/temp')
});

// ...

app.post('/upload', upload.single('foo'), function(req, res) {
  if (req.file) {
    console.dir(req.file);
    return res.end('Thank you for the file');
  }
  res.end('Missing file');
});

Also, body-parser does not currently export a multipart/form-data-capable middleware, so you cannot use that module for handling uploaded files (well, short of passing a base64-encoded string in an application/x-www-form-urlencoded form or something, but that's much less efficient).