Node multer in routes - node.js

I have multer in my app.js like :
var multer = require('multer');
app.use(multer({ dest: './public/img/profile/',
rename: function (fieldname, filename) {
return fieldname;
},
onFileUploadStart: function (file) {
console.log(file.originalname + ' is starting ...')
},
limits: {
files: 1
},
onFileUploadComplete: function (file) {
console.log(file.fieldname + ' uploaded to ' + file.path)
imageUploaded=true;
}
}));
This works but I want to set these settings in a secific route. for example imageRoute.js and not in my app.js. But what should I use instead of app.use() than because I cant access app in my routes. I create routes in my app.js like:
var imageRoutes = require('./routes/imageRoutes')();
app.use('/image', imageRoutes);
imageRoutes.js
module.exports = function(passport) {
var that = this;
// Modules
var express = require('express');
var router = express.Router();
var fs = require('fs');
// Middleware: Checks if user is authenticated removed for more readable code
router.post('/fileupload', that.ensureAuthenticated, function(req, res, next) {
//setup multer here
});
router.post('/fileupload2', that.ensureAuthenticated, function(req, res, next) {
//setup multer here with a different destination path/filename etc
});
return router;
}
i've found this question but it didnt really help me.
UPDATE
I now edited my app.js with :
var multer = require('multer');
var imageRoutes= require('./routes/imageRoutes')(someRepo, multer);
imageRoutes.js
// POST: CREATE avatar
router.post('/avatar', function(req, res) {
router.use(multer({
dest: './public/img/profile/',
rename: function (fieldname, filename) {
return fieldname;
},
onFileUploadStart: function (file) {
console.log(file.originalname + ' is starting ...')
},
limits: {
files: 1
},
onFileUploadComplete: function (file) {
console.log(file.fieldname + ' uploaded to ' + file.path)
imageUploaded=true;
console.log(req.files);
res.redirect('/');
}
}))
});
I see chrome is uploading a file to 100% but then it does nothing. it dosn't log is starting.. or any other error.

You can pass multiple middleware/routers to .use():
var multer = require('multer');
var parseUploads = multer({
dest: './public/img/profile/',
rename: function (fieldname, filename) {
return fieldname;
},
onFileUploadStart: function (file) {
console.log(file.originalname + ' is starting ...')
},
limits: {
files: 1
},
onFileUploadComplete: function (file) {
console.log(file.fieldname + ' uploaded to ' + file.path)
imageUploaded=true;
}
});
// ...
var imageRoutes = require('./routes/imageRoutes')();
app.use('/image', parseUploads, imageRoutes);
If you want to move the logic completely to imageRoutes.js and your multer logic is route-specific, you could do something like:
router.post('/avatar', multer({
dest: './public/img/profile/',
rename: function (fieldname, filename) {
return fieldname;
},
onFileUploadStart: function (file) {
console.log(file.originalname + ' is starting ...')
},
limits: {
files: 1
},
onFileUploadComplete: function (file) {
console.log(file.fieldname + ' uploaded to ' + file.path)
}
}), function(req, res) {
// Here you can check `Object.keys(req.files).length`
// or for specific fields like `req.files.imageField`
res.redirect('/');
});

Related

req.body not working when using multipart/form-data in html form NodeJs/Express

I am using body-parser to get info requested from forms, but when I put enctype="multipart/form-data" in the header of the form, the req.body will not working at all.
However, I have used multer lib in order to upload images as follow:
app.post("/", function (req, res, next) {
var button = req.body.button_name;
if (button == "upload") {
var UserId = 2;
var imageUploadedLimited = 3;
var storage = multer.diskStorage({
destination: function (req, file, callback) {
var dir = "./public/images/uploads/";
if (!fs.existsSync(dir)) {
fs.mkdirSync(dir);
}
dir = "./public/images/uploads/" + UserId;
if (!fs.existsSync(dir)) {
fs.mkdirSync(dir);
}
callback(null, dir);
},
filename: function (req, file, cb) {
cb(null, file.fieldname + "-" + Date.now() + ".jpg");
},
});
const maxSize = 1 * 1000 * 1000;
var upload = multer({
storage: storage,
limits: { fileSize: maxSize },
fileFilter: function (req, file, cb) {
var filetypes = /jpeg|jpg|png/;
var mimetype = filetypes.test(file.mimetype);
var extname = filetypes.test(
path.extname(file.originalname).toLowerCase()
);
if (mimetype && extname) {
return cb(null, true);
}
cb(
"Error: File upload only supports the " +
"following filetypes - " +
filetypes
);
},
}).array("filename2", imageUploadedLimited);
upload(req, res, function (err) {
if (err) {
res.send(err);
} else {
res.send("Success, Image uploaded!");
}
});
}
});
If I print out the button variable from the second line, will show me undefined value. I know body-parser does not support enctype="multipart/form-data". In this case, how I can see the value from the form?
If you are using multer, it needs to be passed as middleware
// Do Something like this
var multer = require('multer')
var storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, 'Your path here')
},
filename: function (req, file, cb) {
cb(null, "fileName")
}
})
var upload = multer({
storage: storage,
})
app.post("/" ,upload.any(), function (req, res, next) {
// NOW YOU CAN ACCESS REQ BODY HERE
});

upload a xls file with postman to a RESTapi made with node/express

In node a can make something like this with and excel file in my directory.
app.post('/api/xlstojson', function(req, res) {
var workbook = XLSX.readFile('tc2.xls');
var sheet_name_list = workbook.SheetNames;
res.json(XLSX.utils.sheet_to_json(workbook.Sheets[sheet_name_list[0]]));
});
I want to test file uploading with postman. There I select POST, form-data, in key I select file instead of text and then in value I upload the tc2.xls file.
In my code I have something like this
app.post('/api/xlstojson', function(req, res) {
var workbook = XLSX.readFile(req.body.file);
var sheet_name_list = workbook.SheetNames;
res.json(XLSX.utils.sheet_to_json(workbook.Sheets[sheet_name_list[0]]));
});
But I get TypeError: path must be a string or Buffer. How should I modify my code to make this work?
Update:
I have been trying with multer, but the file does not appear in the folder
var storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, './public/uploads/')
},
filename: function (req, file, cb) {
var datetimestamp = Date.now();
cb(null, file.fieldname + '-' + datetimestamp + '.' + file.originalname.split('.')[file.originalname.split('.').length -1])
}
});
var upload = multer({ //multer settings
storage: storage
}).single('file');
app.post('/upload', function(req, res) {
upload(req,res,function(err){
if(err){
res.json({error_code:1,err_desc:err});
return;
}
res.json({error_code:0,err_desc:null});
});
});
TypeError: path must be a string or Buffer
You're getting this error because you're not passing the file location. For this to work, you need to pass the location of the file within the upload/ folder
'use strict';
const XLSX = require('xlsx');
var storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, './uploads');
},
filename: function (req, file, cb) {
var datetimestamp = Date.now();
cb(null, file.fieldname + '-' + datetimestamp + '.' + file.originalname.split('.')[file.originalname.split('.').length - 1]);
}
});
var upload = multer({ //multer settings
storage: storage
});
function validate(req, res, next) {
if (!req.file) {
return res.send({
errors: {
message: 'file cant be empty'
}
});
}
next();
}
app.post('/api/xlstojson', upload.single('file'), validate, function (req, res) {
const fileLocation = req.file.path;
console.log(fileLocation); // logs uploads/file-1541675389394.xls
var workbook = XLSX.readFile(fileLocation);
var sheet_name_list = workbook.SheetNames;
return res.json({
json: XLSX.utils.sheet_to_json(workbook.Sheets[sheet_name_list[0]])
});
});
You need to upload the xls file from postman

How to display images stored in Mongodb using Node.Js

I need your help on displaying images stored in MongoDB using Node.JS and express framework.
I've successfully saved the image using this method:
var multer = require('multer');
//var upload = multer({ dest: 'public/Images/' });
var fs = require("fs");
var storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, 'public/Images/')
},
filename: function (req, file, cb) {
//cb(null, file.originalname + '-' + Date.now())
cb(null, Date.now() + '-' + file.originalname);
}
});
var upload = multer({storage: storage});
var user = require('../app/model/user');
app.post('/upload', upload.single('meme'), function (req, res, next) {
if (req.file){
var host = req.hostname;
var filePath = req.protocol + "://" + host + '/' + 'public/Images/' + req.file.originalname;
//console.log(filePath);
var newMeme = new user();
newMeme.meme.imgs = filePath;
newMeme.uploadDate = Date.now();
newMeme.save(function (err) {
if (err)
throw err;
//console('Meme saved');
});
return res.send({
success: true
}) ;
} else {
console.log('failed');
res.send({
success: false
});
}
})
I'm now lost when it comes to displaying the images stored.
These are the stuff I want to display:
please, can someone help? I'm using express JS and ejs as my view engine.
Thanks.

File upload using MeteorJS?

(Cross post from the Meteor forums)
Say I wanted to upload a file to a server that is built with Meteor from another computer through HTTP when the second computer hits a certain API.
So far, I've been able to create such an application using NodeJS, the Express framework, and multer middlewear. I thought it would be easy to move that to Meteor.
NodeJS:
var express = require('express');
var multer = require('multer');
var done = false;
var port = 8888;
var app = express();
//Multer configuration
app.use(multer({
dest: './uploads/',
limits: {
fileSize: undefined
},
rename: function(fieldName, fileName){
return fieldName + Date.now();
},
onFileUploadStart: function(file){
console.log(file.originalname + ' has started downloading!');
},
onFileUploadComplete: function(file){
console.log(file.fieldname + ' has been uploaded to ' + file.path);
done = true;
},
onFileSizeLimit: function(file){
console.log("File " + file.originalname + " is too large");
},
onError: function(){
console.log("ERROR!!");
}
}));
// POST /api/upload
app.post('/api/upload', function(req, res){
if(done === true){
console.log(req.files);
done = false;
}
res.write("Ack!");
res.end();
});
app.listen(port);
However, when I tried to translate the app to Meteor, files were just not uploaded.
MeteorJS
var multer = Npm.require('multer');
var done = false;
//Set up Multer
Picker.middleware(multer({
dest: './fileUploads',
limits: {
fileSize: undefined
},
rename: function(fieldName, fileName){
return fieldName + Date.now();
},
onFileUploadStart: function(file){
console.log("[.]" + file.originalname + " upload has started at " + Date.now());
},
onFileUploadComplete: function(file){
console.log("[.]" + file.originalname + " upload has finished at " + Date.now());
done = true;
},
onFileSizeLimit: function(file){
console.log("[.]" + file.originalname + " file size limit has been reached");
},
onError: function(){
console.log("[.]ERROR!");
}
}));
var postPicker = Picker.filter(function(req, res){
return req.method === "POST";
});
//Actual route, after the middleware has been set up
postPicker.route('/api/upload', function(params, req, res, next){
if(done === true){
console.log(req.files);
done = false;
}
res.write("Ack!");
res.end();
})
When a call is made to the Meteor server, nothing happens. There is no error, and the server does not print anything. However, the caller receives the "Ack!" from the server.
This has me a bit baffled, and I will appreciate any and all help.
Is there a better way of doing this?
Thank you!
FS.Utility.eachFile(event, function(file){
var doc = new FS.File(file);
doc.metadata = {};
_.extend(doc.metadata, {
userId: userId
});
Images.insert(doc, function(err, fileObj){
})
})

How to set different destinations in nodejs using multer?

I'm trying to upload any file using Multer package. It's working fine when I use following code in my server.js file.
var express = require('express'),
app = express(),
multer = require('multer');
app.configure(function () {
app.use(multer({
dest: './static/uploads/',
rename: function (fieldname, filename) {
return filename.replace(/\W+/g, '-').toLowerCase();
}
}));
app.use(express.static(__dirname + '/static'));
});
app.post('/api/upload', function (req, res) {
res.send({image: true, file: req.files.userFile.originalname, savedAs: req.files.userFile.name});
});
var server = app.listen(3000, function () {
console.log('listening on port %d', server.address().port);
});
What I want is to store file at different locations. I had tried following code but it does not work for me.
var express = require('express'),
app = express(),
multer = require('multer');
app.configure(function () {
app.use(multer({
//dest: './static/uploads/',
rename: function (fieldname, filename) {
return filename.replace(/\W+/g, '-').toLowerCase();
}
}));
app.use(express.static(__dirname + '/static'));
});
app.post('/api/pdf', function (req, res) {
app.use(multer({ dest: './static/pdf/'}));
res.send({image: true, file: req.files.userFile.originalname, savedAs: req.files.userFile.name});
});
app.post('/api/image', function (req, res) {
app.use(multer({ dest: './static/image/'}));
res.send({image: true, file: req.files.userFile.originalname, savedAs: req.files.userFile.name});
});
app.post('/api/video', function (req, res) {
app.use(multer({ dest: './static/video/'}));
res.send({image: true, file: req.files.userFile.originalname, savedAs: req.files.userFile.name});
});
var server = app.listen(3000, function () {
console.log('listening on port %d', server.address().port);
});
Means, if I hit http://localhost:3000/api/pdf file should store at 'pdf' folder, if I hit http://localhost:3000/api/video file should store at 'video' folder.
Is there any way to achieve this aim?
Thank you in advance.
Update
Quite a few things have changed since I posted the original answer.
With multer 1.2.1.
You need to use DiskStorage to specify where & how of the stored file.
By default, multer will use the operating system's default directory. In our case, since we are particular about the location. We need to ensure that the folder exists before we could save the file over there.
Note: You are responsible for creating the directory when providing destination as a function.
More here
'use strict';
let multer = require('multer');
let fs = require('fs-extra');
let upload = multer({
storage: multer.diskStorage({
destination: (req, file, callback) => {
let type = req.params.type;
let path = `./uploads/${type}`;
fs.mkdirsSync(path);
callback(null, path);
},
filename: (req, file, callback) => {
//originalname is the uploaded file's name with extn
callback(null, file.originalname);
}
})
});
app.post('/api/:type', upload.single('file'), (req, res) => {
res.status(200).send();
});
fs-extra for creating directory, just in case if it doesn't exists
Original answer
You can use changeDest.
Function to rename the directory in which to place uploaded files.
It is available from v0.1.8
app.post('/api/:type', multer({
dest: './uploads/',
changeDest: function(dest, req, res) {
var newDestination = dest + req.params.type;
var stat = null;
try {
stat = fs.statSync(newDestination);
} catch (err) {
fs.mkdirSync(newDestination);
}
if (stat && !stat.isDirectory()) {
throw new Error('Directory cannot be created because an inode of a different type exists at "' + dest + '"');
}
return newDestination
}
}), function(req, res) {
//set your response
});
Multer is a middleware so you can pass it like this :
app.post('/test/route', multer({...options...}), module.someThing)
or
app.post('/test/route', multer({...options...}), function(req, res){
........some code ......
});
You can make a function like so:
var uploadFnct = function(dest){
var storage = multer.diskStorage({ //multers disk storage settings
destination: function (req, file, cb) {
cb(null, './public/img/'+dest+'/');
},
filename: function (req, file, cb) {
var datetimestamp = Date.now();
cb(null, file.fieldname + '-' + datetimestamp + '.' + file.originalname.split('.')[file.originalname.split('.').length -1]);
}
});
var upload = multer({ //multer settings
storage: storage
}).single('file');
return upload;
};
And then use it in your upload route:
//Handle the library upload
app.post('/app/library/upload', isAuthenticated, function (req, res) {
var currUpload = uploadFnct('library');
currUpload(req,res,function(err){
if(err){
res.json({error_code:1,err_desc:err});
return;
}
res.json({error_code:0,err_desc:null, filename: req.file.filename});
});
});
I tried the solutions shown here but nothing helped me.
ChangeDest attr is not available anymore (As Sridhar proposes in his answer)
I want to share my solution (I am using express 4.13 and multer 1.2):
Imports:
var express = require('express');
var router = express.Router();
var fs = require('fs');
var multer = require('multer');
Storage variable (see documentation here)
var storage = multer.diskStorage({
destination: function (req, file, cb) {
var dest = 'uploads/' + req.params.type;
var stat = null;
try {
stat = fs.statSync(dest);
} catch (err) {
fs.mkdirSync(dest);
}
if (stat && !stat.isDirectory()) {
throw new Error('Directory cannot be created because an inode of a different type exists at "' + dest + '"');
}
cb(null, dest);
}
});
Initializing Multer:
var upload = multer(
{
dest: 'uploads/',
storage: storage
}
);
Using it!
router.use("/api/:type", upload.single("obj"));
router.post('/api/:type', controllers.upload_file);
var storage = multer.diskStorage({
destination: function (req, file, cb) {
if (req.path.match('/pdf')) {
cb(null,<destination>)
}
},
filename: function (req, file, cb) {
}
})
This works in case, the path is unique. You can modify (checking for the end point {req.path}) according to your needs. Though this solution is not dynamic.
we can get path as
const basePath=`${req.protocol}://${req.get("host")}/public/uploads/`;

Resources