Node.js: Multer upload with promise?
13,257
This solution worked for me :
Node v8.4.0 is required for this
//app.js
const fs = require('fs');
const express = require('express');
const cors = require('cors');
const bodyParser = require('body-parser');
const app = express();
app.use(cors({credentials: true, origin: 'http://localhost:4200'}));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
const Uploader = require('./Uploader.js');
const uploader = new Uploader();
app.post('/upload', uploader.startUpload);
//Uploader.js
const util = require("util");
const crypto = require("crypto");
const multer = require('multer');
class Uploader {
constructor() {
const storageOptions = multer.diskStorage({
destination: function(req, file, cb) {
cb(null, __dirname + '/uploads/')
},
filename: function(req, file, cb) {
crypto.pseudoRandomBytes(16, function(err, raw) {
cb(null, raw.toString('hex') + Date.now() + '.' + file.originalname);
});
}
});
this.upload = multer({ storage: storageOptions });
}
async startUpload(req, res) {
let filename;
try {
const upload = util.promisify(this.upload.any());
await upload(req, res);
filename = req.files[0].filename;
} catch (e) {
//Handle your exception here
}
return res.json({fileUploaded: filename});
}
}
Edit : The library "util" provide you a "promisify" method which will give you the possibility to avoid something called the "callback hell". It converts a callback-based function to a Promise-based one.
This is a small example to understand my code above:
const util = require('util');
function wait(seconds, callback) {
setTimeout(() => {
callback();
}, seconds);
}
function doSomething(callType) {
console.log('I have done something with ' + callType + ' !');
}
// Default use case
wait(2 * 1000, () => {
doSomething('callback');
});
const waitPromisified = util.promisify(wait);
// same with promises
waitPromisified(2000).then((response) => {
doSomething('promise');
}).catch((error) => {
console.log(error);
});
// same with async/await
(async () => {
await waitPromisified(2 * 1000);
doSomething('async/await');
})();
Will print :
I have done something with callback !
I have done something with promise !
I have done something with async/await !
Author by
Jack M.
Updated on June 25, 2022Comments
-
Jack M. almost 2 years
I have this express route with multer file-upload. When the upload is complete, I would like to encode the image to base64 and send with response.
However when I do it like this, the code tries to execute the base64 encoding before the file is created to the folder.
Edit: Added storage & upload functions
const storage = multer.diskStorage({ destination: (req, file, callback) => { if (!fs.existsSync('./uploads')) { fs.mkdirSync('./uploads'); } let path = './uploads'; callback(null, path); }, filename(req, file, cb) { let fileExt = file.originalname.substring(file.originalname.lastIndexOf('.')).toLowerCase(); if (!imageFilter(fileExt)) { return false; } else { cb(null, file.originalname); } }, onError: function (err, next) { console.log('error', err); next(err); }, }); const upload = multer({ storage, limits: { fileSize: 1000 * 1000 * 2 // 2 MB } }).single('file'); router.post('/upload', function (req, res) { var directory = 'uploads'; fs.readdir(directory, (err, files) => { if (err) throw err; for (var file of files) { fs.unlink(path.join(directory, file), err => { if (err) throw err; }); } }); upload(req, res, function (err) { if (err) { return res.status(404).json({ success: false, message: 'File is too large. (Max 2MB)' }); } var file = req.file; var base64str = base64_encode('./uploads/' + file.originalname); return res.status(200).json({ success: true, url: 'http://' + ip.address() + ':' + constants.PORT + '/api/uploads/' + file.originalname, image: 'data:image/png;base64,' + base64str }); }); });
What would be the smartest way to achieve the right order of operations. Possibly promises or async/await?