How to use multer function in controller instead of using in route - javascript

I want to Use multer function in controller file But the problem is req.body got undefine when I use postman form-data body to upload images This is link to code that how I am using multer Function but I want use it in my controller
how I want to use it as you can see in below code
const multerHelper = require("../helpers/multer_helper");
Documents: async (req, res) => {
console.log(req.body)
if (!req.body.id) {
console.log(req.body)
logger.warn(error.MANDATORY_FIELDS);
return res.status(500).send(error.MANDATORY_FIELDS)
}
try {
multerHelper.createUserImage
let result = error.OK
logger.info(result);
return res.status(200).send(result)
} catch (err) {
logger.warn(err);
console.log(err);
return res.status(500).send(error.SERVER_ERROR)
}
}
but it throws error like req.body undefine
req.body empty image
postman form-data image
Anyone know how to do it

You can use multer functions and objects in only routes not in controller if you want to use it in controller you have to write storage and upload functions in controllers, here I have used multer error handling and I am uploading multiple images
Documents: async (req, res) => {
if (!req.headers.room_id) {
logger.warn(error.MANDATORY_FIELDS);
return res.status(500).send(error.MANDATORY_FIELDS)
}
try {
let storage = multer.diskStorage({
destination: function (req, file, cb) {
let id = req.headers.room_id;
let path = `tmp/daily_gasoline_report/${id}`;
fsextra.mkdirsSync(path);
cb(null, path);
},
filename: function (req, file, cb) {
// console.log(file);
let extArray = file.mimetype.split("/");
let extension = extArray[extArray.length - 1];
cb(null, file.fieldname + '-' + Date.now() + "." + extension);
}
})
var upload = multer({ storage: storage }).array('images', 100);
upload(req, res, function (err) {
if (err) {
console.log(err);
return res.end("Error uploading file.");
} else {
res.end("File has been uploaded");
}
});
let result = error.OK
logger.info(result);
return res.status(200).send(result)
} catch (err) {
logger.warn(err);
console.log(err);
return res.status(500).send(error.SERVER_ERROR)
}
}

Do you have a parser?
How do you parse the data?
Your gonna need to use something that gives you this data something like:
https://www.npmjs.com/package/express-fileupload
this package helps you to parse the form data and the files data itself.

Related

What is the correct way to make multer work with Node and Express here?

I am trying to create a route through which I can upload photos. However as I made so,e changes it stopped working and I am not sure how to make it work.
const multer = require('multer');
// MULTER STORAGE
const multerStorage = multer.diskStorage({
destination: (req, file, cb) => {
cb(null, '/upload');
},
filename: (req, file, cb) => {
const ext = file.mimetype.split('/')[1];
// Saving format: user-UserId-DateStamp.ext
//e.g user-608d55c7e512b74ee00791de-1621992912638.jpeg
cb(null, `user-${req.body.userId}-${Date.now()}.${ext}`);
},
});
//MULTER FILTER
const multerFilter = (req, file, cb) => {
//mimetype always starts with image/ then png or jpeg or..
if (file.mimetype.startsWith('image')) {
cb(null, true);
} else {
cb(new AppError('You are only allowed to upload image files.', 400), false);
}
};
const uploadDirectory = multer({
storage: multerStorage,
fileFilter: multerFilter,
});
//exports.uploadPhoto = uploadDirectory.single('photo');
//app.use(express.static('./uploads'));
// INCLUDE ERROR CLASS AND ERROR CONTROLLER
const AppError = require('../utils/appError.js');
const errorController = require('./errorController.js');
const { Mongoose } = require('mongoose');
The main problem Im guessing is in this block
//UPLOAD PHOTO
exports.uploadPhoto = uploadDirectory(async (req, res) => {
console.log(req.body);
console.log(req.file);
try {
const newPhoto = await photoModel.create(req.file);
newPhoto.save().then((result) => {
console.log('Saved');
res.status(201).json({
status: 'success',
// data: JSON.parse(JSON.stringify(newPhoto.file)),
});
});
} catch (err) {
console.log('Error in upload');
errorController.sendError(err, req, res);
}
}).single('photo');
Can anybody let me know how to correctly write the exports.uploadPhoto
Originally the last function looked like this
exports.uploadPhoto = async (req, res) => {
console.log(req.body);
console.log(req.file);
try {
const newPhoto = await photoModel.create(req.file);
newPhoto.save().then((result) => {
console.log('Saved');
res.status(201).json({
status: 'success',
// data: JSON.parse(JSON.stringify(newPhoto.file)),
});
});
} catch (err) {
console.log('Error in upload');
errorController.sendError(err, req, res);
}
};
The multer middleware function, in your case uploadDirectory, is usually used before other middleware functions/controllers where you have your business logic (e.g. uploadPhoto).
app.post('/upload', uploadDirectory.single('photo'), uploadPhoto);
Keep your original uploadPhoto function and with the above code you'll have access to the data and file through reg.body and req.file, respectively.
This Request Parsing in Node.js Guide (it's free) will help you with file uploads in Node.js.

Req,File.Path remains undefined and i am using multer due to vague documentation,i cannot fully understant it?

I,m using mutler to upload a image and i am constantly getting this error.
And i think the following function triggers it.
The complete js code is attached below.Thanks in advance!
const upload = multer({
dest: "/uploads"
});
app.post(
"/game",
upload.single("file" /* name attribute of <file> element in your form */),
(req, res) => {
const tempPath = req.file.Path;
const targetPath = path.join(__dirname, "/uploads/"+imgname+".jpg");
imgname++;
if (path.extname(req.file.originalname).toLowerCase() === ".jpg") {
fs.rename(tempPath, targetPath, err => {
if (err) return handleError(err, res);
res
.status(200)
.sendFile(__dirname + '/game.html');
});
} else {
fs.unlink(tempPath, err => {
if (err) return handleError(err, res);
res
.status(403)
.contentType("text/plain")
.end("Only .jpg files are allowed!");
});
}
}
);
Js file link: https://filebin.net/fd7q89ji16xftst4
Your code doesn't have a variable called imgname. After checking the code, it looks like you need to pass the file name for the imgname. You can use req.file.filename to get the name of the uploaded file.
Full code:
const upload = multer({
dest: "/uploads"
});
app.post(
"/game",
upload.single("file" /* name attribute of <file> element in your form */),
(req, res) => {
const tempPath = req.file.Path;
const imgname = req.file.filename;
const targetPath = path.join(__dirname, "/uploads/"+imgname);
imgname++;
if (path.extname(req.file.originalname).toLowerCase() === ".jpg") {
fs.rename(tempPath, targetPath, err => {
if (err) return handleError(err, res);
res
.status(200)
.sendFile(__dirname + '/game.html');
});
} else {
fs.unlink(tempPath, err => {
if (err) return handleError(err, res);
res
.status(403)
.contentType("text/plain")
.end("Only .jpg files are allowed!");
});
}
}
);

Submitting form with body-parser

I am trying to understand how routing works with express.
With some code redacted, I have the following in my server.js
const multer = require("multer"); //for uploading image
const bodyParser = require("body-parser"); //for adding employee(below)
app.get("/employees/add", (req, res) => {
res.sendFile(path.join(__dirname, './views', 'addEmployee.html'));
});
app.get("/images/add", (req, res) => {
res.sendFile(path.join(__dirname, './views', 'addImage.html'));
});
app.get("/employees", (req, res) => {
data.getAllEmployees().then((data) => {
res.json(data);
}).catch(function(err) {
console.log("An error was encountered: " + err);
});
});
app.get("/images", (req, res) => {
let imagePath = './public/images/uploaded';
fs.readdir(imagePath, function(err, items) {
if (items.length == 0) {
console.log("No images");
res.send("Error reading images directory<br/><h3>Return to <a href='/'><em>HOME</em></a></h3>");
} else {
//res.json(items);
var finalString = "Images: " + JSON.stringify(items) + "<br/><h3>Return to <a href='/'><em>HOME</em></a></h3>";
res.send(finalString);
}
});
});
const storage = multer.diskStorage({
destination: "./public/images/uploaded",
filename: function (req, file, cb) {
cb(null, Date.now() + path.extname(file.originalname));
}
});
const upload = multer({ storage: storage });
app.use(express.static("./public/images/uploaded"));
app.post("/add-image", upload.single("imageFile"), (req, res) => {
const formFile = req.file;
res.send("<p>Your submission >> " + JSON.stringify(formFile) + " was successful</p><br/><h3>Return to <a href='/'><em>HOME</em></a></h3>");
});
My data-service.js has a function defined as,
module.exports.addEmployee = function(employeeData) {
return new Promise((resolve, reject) => {
(typeof employeeData.isManager === 'undefined') ? false : true;
employeeData.employeeNum = employees.length + 1;
employees.push(employeeData);
resolve(employees);
});
}
Where the employees array resides in an employees.json file.
I have no issues getting the uploading images working. It uploads, and sends me back a response. Now, I am trying to get Adding a New Employee to work with body-parser, however I am running into a few issues.
My server.js waits for:
app.get("/employees/add", (req, res) => {
res.sendFile(path.join(__dirname, './views', 'addEmployee.html'));
});
And then redirects to my addEmployee.html which has the action, action="/add-employee", redirecting back to my server.js with the route,
app.post("/add-employee", (req, res) => {
//do something
});
I have tried calling it with something along the lines of,
app.post("/add-employee", (req, res) => {
data.addEmployee();
//etc
});
having defined addEmployee as in the second code snippet.
And this, (obviously, otherwise I wouldnt be here lol), doesn't quite work. I feel like, although syntax may be an issue, I am misconstruing the routing logic here. What am I missing?

Encrypt the uploaded file before saving to disk using Node.js

Currently, I am using multer library to save files on File system. This application is using Node and Express.
I can save the file first on server and then encrypt it. Later on delete the unencrypted file. However, I do not want to add unencrypted file on server directly. So, I am looking for a way to encrypt the incoming file from the front end and then save it to disk.
const defaultFolder = 'upload';
const filePath = resolveHome(process.env.FILE_STORAGE_LOCATION || defaultFolder);
const key = 'test';
const cipher = crypto.createCipher('aes-256-cbc', key);
const decipher = crypto.createDecipher('aes-256-cbc', key);
const upload = multer({
storage: multer.diskStorage({
destination: filePath,
filename: (req, file, cb) => {
const parts = file.originalname.split('.');
const ext = parts.pop();
const name = parts.join('.');
cb(null, name + '-' + Date.now() + '.' + ext);
},
}),
}).single('file');
app.post('/upload', (req, res) => {
upload(req, res, err => {
if (err) {
return res.status(400).send({
error: 'The request was invalid',
fileName: req.file.originalname,
});
}
return res.status(200).send({
fileName: req.file.filename,
});
});
});
I tried to use crypto library to encrypt the file but it's not working. I believe the req.cipher is invalid as I would normally use req.file to get reference to the file.
app.post('/upload', (req, res) => {
upload(req, res, err => {
output = fs.createWriteStream(filePath + '/' + req.file.originalname);
req.pipe(cipher).pipe(output).on('finish', () => console.log('Encrypted file written on disk'));
if (err) {
return res.status(400).send({
error: 'The request was invalid',
fileName: req.file.originalname,
});
}
return res.status(200).send({
fileName: req.file.originalname,
});
});
});
I had tried to just write file without using cipher and file was empty. Adding this information in case it helps.
req.pipe(output).on('finish', () => console.log('Encrypted file written on disk'));
Can you try this
app.post('/upload', function(req, res) {
upload(req, res, function(err) {
var fileName = req.file.destination +"\\"+ req.file.filename
var input = fs.createReadStream(fileName);
var output = fs.createWriteStream(fileName + ".enc");
input.pipe(cipher).pipe(output);
output.on('finish', function() {
fs.unlink(fileName, (err) => {
if (err) throw err;
console.log('Encrypted file written to disk!');
res.end('Encrypted file written to disk!')
});
});
})
})

Error: Can't set headers after they are sent in express-fileupload

app.post('/profile', function(req, res) {
// save file
if (req.files) {
let sampleFile = req.files.sampleFile;
sampleFile.mv('/somewhere/on/your/server/filename.jpg', function(err) {
if (err)
return res.status(500).json(err);
});
}
// do some other stuff
// .............
res.status(200).json(result);
});
I know the problem is caused by return res.status(500).json(err). I can solve the problem by moving res.status(200).json(result) after if (err) block. Since upload file is optional, the user may posting other data without any uploading files. My question is how to send status 200 with a json result after processed other stuff if the solution is
if (err)
return res.status(500).json(err);
res.status(200).json(result);
As was pointed above the problem is you are sending the success reponse outside of the callback.
The solution is to do "other stuff" within the callback.
This should fix the issue -
app.post('/profile', function(req, res) {
// save file
if (req.files) {
let sampleFile = req.files.sampleFile;
sampleFile.mv('/somewhere/on/your/server/filename.jpg', function(err) {
if (err) return res.status(500).json(err);
doOtherStuff();
res.status(200).json(result);
});
} else {
doOtherStuff();
res.status(200).json(result);
}
});
// Write a do other stuff function
function doOtherStuff() {
// do stuff
}
EDIT Adding answer with Promises to avoid code repetition.
function moveFile(file, somePlace) {
return new Promise((resolve, reject)=>{
file.mv(somePlace, function(err) {
if (err) return reject(err);
resolve();
});
});
}
app.post('/profile', function(req, res) {
// save file if present
const fileMovePromise = req.files ?
moveFile(req.files.sampleFile, '/somewhere/on/your/server/filename.jpg')
:
Promise.resolve('No file present');
fileMovePromise
.then(() => {
// do other stuff
})
.catch(err => {
res.status(500).json(err);
});
});
You could use a form of middleware to check if the post is uploading files, the act on the file upload before continuing, have a look at middleware with express here: http://expressjs.com/en/guide/using-middleware.html
With middleware you can do your check to see if the file needs uploading and then call next, otherwise just call next.
app.use('/profile', function (req, res, next) {
if (req.files) {
let sampleFile = req.files.sampleFile;
sampleFile.mv('/somewhere/on/your/server/filename.jpg', function(err, data) {
if (err) {
res.status(500).json(err);
} else {
req.data = data
next()
}
});
}
res.status(200);
}, function (req, res) {
res.status(500).json(req.data);
})
If you are using Node for express, the res param contains res.headersSent, which you can check if the headers have already been sent.
if(res.headersSent) {}
You can also find out a lot more here: https://nodejs.org/api/http.html#http_response_headerssent

Categories

Resources