Cannot retrieve body text along with upload, Express js - node.js

I have a form that asks for a text and a file. I use multer for the file upload. The problem is I cannot retrieve the text with req.body if i use enctype=multipart/form-data
Route file
router.post('/new-job', function(req,res,next){
upload(req,res,function(err) {
if(err) {
return res.end("Error uploading file.");
}
});
var newJob = {
job_name: req.body.job_name, //Cannot retrieve this two
job_desc: req.body.job_desc,
};
var newJobData = new Jobs(newJob);
newJobData.save(function(err,user){
if(err)
console.log(err);
});
res.render('jobs/new-job', {job_added:true});
});
Multer configs
var multer = require('multer');
var storage = multer.diskStorage({
destination: function (req, file, callback) {
callback(null, 'public/uploads');
},
filename: function (req, file, callback) {
callback(null, file.originalname);
}
});
Notes
I used method post
If i log the req.body.job_name it returns an undefined
If i remove the enctype=multipart/form-data i can retrieve the text just fine, though i cannot upload the file

You cannot access req.body contents until you're parsed the request, so either move your code inside your upload() callback, or get rid of the explicit upload() call entirely and just put upload before your route handler:
router.post('/new-job', upload, function(req, res, next) {
var newJob = {
// ...

Related

Set filname by id generated by mongoose using multer node js

I am new in Node js API and I'm trying to upload an Image using multer + express + mongoose + postman
CODE:
var storage = multer.diskStorage({
destination: function (request, file, callback) {
callback(null, 'public/images/course');
},
filename: function (request, file, callback) {
return callback(null, file.originalname)
}
});
var upload = multer({storage : storage})
router.post('/course', upload.single('thumbnail'),async(req, res) => {
try{
var course = new Course({
name : req.body.name,
thumbnail : "placeholder" // set to path where file is uploaded
})
await course.save()
res.status(201).send(course)
}catch(e){
res.status(400).send(e)
}
})
I use postman to post request using form data and it creates an image with its originalFilename but i want the filename to be id generated by mongoose and i have seen somewhere that i can use filesystem for that but is there any way i can upload file after id is generated because when i do like this
var storage = multer.diskStorage({
destination: function (request, file, callback) {
callback(null, 'public/images/course');
},
filename: function (request, file, callback) {
if (request.data) {
console.log(file)
// TODO: consider adding file type extension
fileExtension = file.originalname.split('.')[1]
return callback(null, `${request.path}-${request.data._id.toString()}.${fileExtension}`);
}
// fallback to the original name if you don't have a book attached to the request yet.
return callback(null, file.originalname)
}
});
var upload = multer({storage : storage}).single('thumbnail')
router.post('/course',(req, res) => {
console.log(req.body)
const course = new Course({
name : req.body.name,
thumbnail : req.body.name
})
//console.log(course)
req.data = course
//console.log(req.file)
upload(req, res, function (err) {
if (err instanceof multer.MulterError) {
// A Multer error occurred when uploading.
} else if (err) {
// An unknown error occurred when uploading.
}
// Everything went fine.
})
})
Then i got request body empty.
Thanks in advance

Express, Nodejs use Multer for different Services

I am using express server and multer for upload file on different services (local, azure, cloudinary, amazon s3 etc).
For that i am using different module of multer multer-azure, multer-cloudinary etc.
I need this configuration will be applied to user wise and that information comes from the database.
So i need a extra call to fetch data from database before multer come in action.
I am able to call database query but when i am trying to call multer function, req parameter coming blank. Here is what i am doing.
var multerUtility = require('./upload/multer.utility');
let multer = new multerUtility().getActiveMulterService();
router.post('/', getMetadataConfiguration, multer, (req, res, next) => {
console.log('========== req ==========', req.file); // It is coming blank
console.log('========== req ==========', req.body); // It is coming blank
});
Here is first middleware function, which fetch data from database to verifiy which service will use to upload file.
function getMetadataConfiguration(res, req, next) {
var conn = new jsforce.Connection({
loginUrl : config.org_url,
});
var records = [];
conn.login(username, password, function(err, userInfo) {
if (err) {
return console.error(err);
}
conn.query("query", (err, result) => {
if(err) {
res.status(500).send(err);
}
console.log('=========== result=========', result);
req.serviceConfig = result.records[0];
next();
});
});
}
And here is my MulterUtility Class to handle configuration:
upload/multer.utility.js
class MulterUtility {
constructor() {
}
getActiveMulterService(req, res, next) {
var multerConfiguration;
if(req.serviceConfig.service == 'azure') {
multerConfiguration = multer({
storage: multerAzure({
connectionString: config.azure.connectionString,
account: config.azure.account,
key: config.azure.key,
container: config.azure.container
})
}).single('image');
} else if(req.serviceConfig.service == 'cloudinary') {
multerConfiguration = multer({
storage: cloudinaryStorage({
cloudinary: cloudinary,
folder: config.storageFolder
// allowedFormats: ['jpg', 'png', 'jpeg']
})
}).single('image');
} else if(req.serviceConfig.service === 'amazon') {
multerConfiguration = multer({
storage: multerS3({
s3: s3,
bucket: 'mycontainer',
acl: 'public-read',
contentType: multerS3.AUTO_CONTENT_TYPE,
metadata: function (req, file, cb) {
cb(null, {fieldName: file.fieldname});
},
key: function (req, file, cb) {
cb(null, Date.now().toString() + '-' + file.originalname)
}
})
}).single('image');
} else if(req.serviceConfig.service === 'local') {
multerConfiguration = multer({
storage: multer.memoryStorage()
}).single('image');
}
return multerConfiguration;
}
}
module.exports = MulterUtility;
After executing multer, i am not recieving a req.file or req.body params what multer sets after uploading file.
For now you can consider the 'local' file upload as mentioned in last condition.
The problem is that you call the method getActiveMulterService once before the router. But you need to call it for each post. Try something like this:
var multerUtility = require('./upload/multer.utility');
let multers = new multerUtility();
router.post('/',
getMetadataConfiguration,
(req, res, next) => multers.getActiveMulterService(req, res, next)(req, res, next),
(req, res, next) => {
console.log('========== req ==========', req.file); // It is coming blank
console.log('========== req ==========', req.body); // It is coming blank
});
And in this function you have arguments in the wrong order:
getMetadataConfiguration(res, req, next)
// ==>
getMetadataConfiguration(req, res, next)
Hi this has largely been answered already. The solution is to manual add your file object back onto your req.body object during the process.
Full solution is found here

How to get req.body parameters in multer s3

var upload = multer({
storage: multerS3({
s3: s3,
bucket: 'bucket',
metadata: function(req, file, cb) {
cb(null, {
fieldName: file.fieldname
});
},
key: function(req, file, cb) {
console.log('req.body', req.params.id); //not getting
console.log('req.body', req.body);
//Not getting param here that passed in api
//Need to save file on s3 at specific location i.e /foldername/filename
//But the folder name not getting from API
cb(null, file.originalname)
}
}) }).array('userFile', 1);
Above is multer s3 code
app.post('/saveData', function(req, res, next) {
upload(req, res, function(err) {
console.log('err' + err);
var status = '';
var result = '';
var link = '';
if (err) {
status = false;
} else {
status = true;
}
result = {
"status": status,
"link": link
}
});
res.send(result); });
Above code where calling multer upload function. I am parsing data in API (from Angular2, set -Content-Type": "multipart/form-data) as formdata
let formData: FormData = new FormData();
formData.append('userFile', file);
formData.append('fileName', fileName);
I require the req.body data from API like folder name and other, so I can put the file to specific place on S3. Need req.body data inside the key: function(req, file, cb) { of multerS3.
It seems to be a bug in multer, but as said here you can reorder the parameters when sending.
https://github.com/expressjs/multer/issues/322#issuecomment-191642374
Reading the source code of dropzone.js i've figured out that the problem is that S3 expects the file to be the last paramater of your formdata
If your file input is the last input of your form, you should also try to pass the reference of the form tag when you make a new instance of FormData()
<form
id="myForm"
className="col-md-10 col-md-offset-1"
>
so pass id like this: new FormData(document.getElementById(myForm)
then you should find in your key callback function req.body with the input values of your form

Format issue while uploading Jpg file with NodeJS Multer module

I'm using Multer to upload jpg file from Postman to a node.js back-end.
I assume the "upload" goes well because the image is located at the right place with the right name and the right size after the POST request
Unfortunately, when I try to open the image file it doesn't open as a jpg image even though the extension is .jpg
I used checkFileType website and apparently, the file type becomes application/octet-stream after the upload.
I didn't specify any headers in the request.
Here is my Postman setup
Here is the response
Here is the code in the Node API side
var localWorkLocation = '/Users/noste/CarFixer/Pictures/';
exports.createBinary = function (req, res) {
var location = localWorkLocation + req.params.platenumber;
var storageOptions = multer.diskStorage({
destination: function (req, file, callback) {
mkdirp(location, err => callback(err, location));
callback(null, location);
},
filename: function (req, file, callback) {
//if (!file.originalname.match(/\.(jpg|jpeg|png)$/)) {
// return callback(new Error('Only image files are allowed!'), false);
//}
callback(null, file.originalname);
},
});
var upload = multer({storage : storageOptions}).single('picture');
upload(req, res, function(err){
console.log(req.file);
if(err) {
return res.end(err.message);
}
res.send(req.file);
});
};
I've tried to upload a .txt file and it's still readable after upload.
Is there a place where I need to specify that I want to keep the jpg format ?
here's the storage configuration u need .. change the naming according to your code
var path = require('path');
var storage = multer.diskStorage({
destination: function(req, file, callback) {
callback(null, './uploads');
},
filename: function(req, file, callback) {
var fname = file.fieldname + '-' + Date.now() + path.extname(file.originalname);
callback(null, fname);
}
});
And here's another answer for multiple files upload

NodeJS: 'multer' file upload callback function

I am using 'multer' plugin for file upload. I want to call another function after file upload successfully.
Here my code:
module.exports.uploadFile = upload.single('file', '_id'), function (req, res, next) {
console.log('Uploade Successful');
}
var upload = multer({
storage: multer.diskStorage({
destination: './Media/ChatDocUpload',
filename: function (req, file, cb) {
var dest = './Media/ChatDocUpload';
//query string params
var _chatMessageID = req.query.chatMessageID;
var _ext = file.originalname.substring(file.originalname.indexOf("."));
var _fileName = _chatMessageID + _ext;
cb(null, _fileName);
}
})
});
I want to call my new function after image uploaded. Using this code i can upload image successfully, but not get call callback function.
I need call new function after image uploading completed.
//I need to call this function after image fully uploaded
var uploadSuccessFn = function () {
//code
}
You could maybe change the code to use 2 functions in your POST handler:
module.exports = {uploadFile: uploadFile, afterUpload: afterUpload};
function uploadFile(){
upload.single('file', '_id');
}
function afterUpload(req, res, next) {
console.log('Uploade Successful');
}
var upload = multer({
storage: multer.diskStorage({
destination: './Media/ChatDocUpload',
filename: function (req, file, cb) {
var dest = './Media/ChatDocUpload';
//query string params
var _chatMessageID = req.query.chatMessageID;
var _ext = file.originalname.substring(file.originalname.indexOf("."));
var _fileName = _chatMessageID + _ext;
cb(null, _fileName);
}
})
});
Then simply require the file and use it in the post request handler:
.
.
var imageUpload = require('./handler');
app.post('/image/upload',imageUpload.uploadFile,imageUpload.afterUpload);
.
.
The function (inside the process) when you are calling the process of upload, is the callback fuction just use it . you are written line console.log it means your callback fuction is called when your file is upload but you are not using ..
can be done like this:-
function(req,res){ //callback function
res.json({message:"file uploaded successfully"});
}
it will give you json response.
I suggest that you create your own customized storage engine based on multer:
Multer Storage Engine
Then you just add the customized code after your file has been uploaded. Something like this:
MyCustomStorage.prototype._handleFile = function _handleFile (req, file, cb) {
this.getDestination(req, file, function (err, path) {
if (err) return cb(err)
var outStream = fs.createWriteStream(path)
file.stream.pipe(outStream)
outStream.on('error', cb)
outStream.on('finish', function () {
// Insert here whatever you want to do...
console.log('Successfully Uploaded');
cb(null, {
path: path,
size: outStream.bytesWritten
})
}) })}
Please note that you have to use var fs = require('fs') to make it work. Hope this help.
In your code from where you calling upload put an if condition which checks the checks the callback response. If response null then you can call another function in that condition else show some error.
I guess the function you trying call will show some kind of success message to the user.
try like this
var storage = multer.diskStorage({
destination: function (req, file, cb) {
return cb(null, './Media/ChatDocUpload')
},
filename: function (req, file, cb) {
var _chatMessageID = req.query.chatMessageID;
var _ext = file.originalname.substring(file.originalname.indexOf("."));
var _fileName = _chatMessageID + _ext;
return cb(null, _fileName);
}
})
var upload = multer({ storage: storage })
module.exports.uploadFile = upload.single('file'), function (req, res, next) {
console.log('Uploade Successful');
// you function after uploading images
}

Resources