Dynamically reload multer with new limits fileSize value - node.js

I'm using these lines to initialize multer:
file_size_limit=1000000;
var multer = require('multer');
upload = multer({ dest: 'upload/', limits: { fileSize: global.file_size_limit }}).array('fileUploaded');
And in the route i use for example:
router.post('/', global.upload, function(req, res, next) {
What i have already achieved with busboy is that, i can create an admin section, and change the file size limit, which restricts the size of uploaded files. There is no need to restart the server as the var busboy = ... functionality lies within the router.post('/', function(req, res, next){}) ..
I am not able to do this in multer without restarting the server.
Is it possible to re-assign upload variable with new multer settings on a given route being accessed?
Could be something like this...
router.get('/', function(req, res, next){
global.upload = multer({ dest: 'upload/', limits: { fileSize: new_file_size_limit }}).array('fileUploaded');
});
Right now all i can think of is to save the new setting of fileSize in a database and then write a .js file which would make the server restart using nodemon (which monitors code changes and restarts if any)...
Can this be done without restarting the server?

Okay, i found how to do this. For others facing this problem, i'm posting the solution here. The upload variable can be nested inside the req, res of the route. (It is not necessary that upload variable is a parameter in the route itself)
The code would look like this:
router.post('/', function(req, res, next) {
var upload = multer({ dest: 'upload/', limits: { fileSize: req.app.locals.size }}).array('myfile');
upload(req, res,function(err) {
if(err) {
return res.end(err.toString());
}
console.log(req.body);
var tmp_path = req.files[0].path;
var target_path = '/home/' + req.files[0].originalname;
fs.rename(tmp_path, target_path, function(err) {
if (err) throw err;
});
res.redirect('back');
});
});

Related

Azure Node.js Easy API Middleware

I've got an Azure node.js app. I wanted to add 'multer' middleware, for dealing with file uploads, to only one POST easy-api.
For example, I have the file ./api/upload-files.js, which is supposed to look something like this:
module.exports = {
"post" : async (req, res, next) => {
// ...
}
};
And I can quite easily add the multer middleware to the ./app.js file, where the express app is initialized:
const multer = require('multer');
app.post('*', multer({ storage: multer.memoryStorage() }).any());
But if I don't want to add multer middleware to every post endpoint, but just to the one in ./api/upload-files.js, how do I do that?
Original comment
This is something related with the way you are instanciating the express instance in your app.
If you do not wish to use the multer middleware for some request you can just use the function you want in the request itself, avoiding to call the multer function when passing the arguments to the request method.
One example for a get endpoint:
app.get('/getrequest', (req, res, next) => {
console.log('Someone made a get request to your app');
})
One example for a post endpoint:
app.post('/postrequest', (req, res, next) => {
console.log('Someone made a POST request to your app');
})
Keep in mind that you add or remove middleware functions in express this way.
app.use('/user/:id', function (req, res, next) {
console.log('I am a middleware!')
next()
}, function (req, res, next) {
console.log('I am another function')
next()
})
Here are the docs
Edit
Could maybe this code adapt to your usecase?
app.post('*', checkUseMulter);
function checkUseMulter(req, res, next) {
if (['/mypathwithoutmulter', '/myotherpath'].includes(req.path)) {
return next();
}
return multer({ storage: multer.memoryStorage() }).any();
}

File uploading in express using multer

I am trying to upload image using multer but getting error,uploads is not a function.Here is my code
var multer = require('multer');
var uploads = multer({dest: './images'});
app.post('/uploading', uploads.single('image'), function(req, res) {
console.log(req.file);
var file = __dirname + '/' + req.file.filename;
uploads(req.file.path, file, function(err) {
if (err) {
console.log(err);
res.send(500);
} else {
res.json({
message: 'File uploaded successfully',
filename: req.file.filename
});
}
});
var multer = require('multer');
var uploads = multer({dest: './images'});
app.post('/uploading', uploads.single('image'), function(req, res) {
yourModel.create(req.body,function(err,result){
console.log(result);
});
});
Its quite obvious; uploads is not a function but uplaod is. So use
upload.single('image')
As #Kuldeep said you don't have to the uploads(filePath, file, (err) => {...}) inside the route.
When you are using multer as middleware (the middle function) multer will automatically upload the file and expose the filename, originalName etc to req.file object inside the route
var multer = require('multer');
var uploads = multer({dest: './images'});
app.post('/uploading', uploads.single('image'), function(req, res) {
// here just write the success or error login
});
Reference You can check here: here
EDIT: The above code will upload the file with hex string as filename without any extension.
In order to add rename function you need to use diskStorage. Here is the code taken from this github issue page.
var storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, './images/')
},
filename: function (req, file, cb) {
crypto.pseudoRandomBytes(16, function (err, raw) {
cb(null, raw.toString('hex') + Date.now() + '.' + mime.extension(file.mimetype)); //this is the rename func
});
}
});
var uploads = multer({ storage: storage });
Now you can use the uploads variable as middleware as shown in the above snippet.
I haven't found a great, soup-to-nuts guide on using Multer (the website is just a little lacking for newbies) so here's my stab at it.
After using:
npm install multer --save
to add it to your project.
For me, I wanted to capture files on a specific route, namely:
/customers/:id/upload
So, I went into my customers.js route file and added:
var multer = require('multer');
as well as the code to set up the storage (diskStorage) and filename configuration tweaks:
var storage=multer.diskStorage({
destination: function(req,file,cb){
cb(null,'/uploads/');
},
filename: function(req,file,cb){
cb(null,file.fieldname+'-'+Date.now());
}
});
I could then create the upload middleware object that lets me specify, per route, how I would like Multer to handle file uploads. On the route above, I only want to receive one file with a particular internal filename so my customers.js route file looks like this:
router.post('/:id/targets/upload', upload.single('connections'), function(req,res,next){
console.log("Router:POST: Companies/:_id/upload");
console.log(req.file);
...
});
All of the examples I saw had stuff being added to the app.js file but these seemed a bit awkward and contrived as examples. Every route may have different file handling needs so it just seemed more appropriate, to me, to configure Multer on a per-controller basis. YMMV.

Configuring multer to upload files to nodejs server

The express Router is setup as such:
var router = require('express').Router();
var multer = require('multer');
var uploading = multer({
dest: './uploads/',
limits: {fileSize: 1000000, files:1},
});
router.post('/upload', uploading.single('avatar'), function(req, res) {
console.log('success');
});
module.exports = router;
I am attempting to upload files:
curl -F "image=#/Users/runtimeZero/Desktop/nassau.jpg" localhost:3000/auth/upload
The express server throws the below error:
Error: Unexpected field
at makeError (/Users/.../node_modules/multer/lib/make-error.js:12:13)
at wrappedFileFilter (/Users/../node_modules/multer/index.js:39:19)
...
...
at HeaderParser.push (/Users/.../node_modules/multer/node_modules/busboy/node_modules/dicer/lib/HeaderParser.js:46:19)
at Dicer._oninfo (/Users/.../node_modules/multer/node_modules/busboy/node_modules/dicer/lib/Dicer.js:197:25)
From multer documents this seems pretty straight forward. However, not so much when actually using it. What am i missing ?
If you look at the multer readme you will see that multer() returns an object that contains various functions that return different middleware, depending on your needs.
For example, to accept a single file whose name is 'avatar':
var upload = multer({dest: './uploads/'});
router.post('/upload', upload.single('avatar'), function(req, res) {
console.log('success');
});

multer won't recognize files with PUT

So I just installed node and fire up a little HTTP server with express. I'm trying to upload files with multer and HTTP PUT but it seems as multer can't handle PUTting files.
Doing the same thing with POST works just fine.
This is my main.js:
var express = require('express');
var multer = require('multer');
var storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, './uploads')
},
filename: function (req, file, cb) {
cb(null, file.originalname)
}
});
var upload = multer({ storage: storage });
var app = express();
app.get('/', function (req, res) {
res.send('Up and running');
});
app.put('/up/:file', upload.any(), function (req, res, next) {
console.log('files: ' + req.files);
console.log(req.params.file);
res.send('got that');
})
app.post('/up', upload.any(), function (req, res, next) {
res.send('got that');
})
var server = app.listen(8888, function(){
var host = server.address().address;
var port = server.address().port;
console.log('Example app listening at http://%s:%s', host, port);
});
Using curl I can POST files just fine, e. g. with curl --form "file=#someFile.jpg" http://localhost:8888/up.
I tried putting a file with curl http://localhost:8888/up/someFile.jpg --upload-file someFile.jpg as well as with curl -i -T someFile.jpg http://localhost:8888/up/someFile.jpg but it just won't work. req.files is always undefined.
Question/TL;DR: Is multer just not capable of accepting files via PUT? How can I receive files per PUT with express? Actually, I don't need express ... a plain node solution would be enough.
Your two forms of curl for sending your PUT request are not sending multipart/form-data bodies, they are sending the raw file contents as the body instead. multer does not support that, as it is expecting multipart/form-data-encoded forms.
To support these raw file uploads, you will need to handle them yourself (e.g. piping the request to disk or wherever). For example:
app.put('/up/:file', function (req, res, next) {
// TODO: optionally validate `req.headers['content-type']`
// TODO: sanitize `req.params.file` before
// using it to create the filename
var filename = req.params.file;
var diskStream = fs.createWriteStream(path.join(__dirname, 'uploads', filename));
req.pipe(diskStream).on('finish', function() {
res.send('got that');
});
});

Set multer properties inside an express route

Instead of attaching multer to the entire express app, i am trying to include it just for specific routes, which is better since you will be preventing uploads to every route handling post.
Problem is, i am unable to set it properties inside a route.
var router = require('express').Router(),
multer = require('multer');
router.post('/uploads', function (req, res, next) {
multer({
dest: req.app.get('cfg').uploads.dir
});
console.log(req.files); process.exit();
});
Here, req.files is undefined.
The same thing happens if i put multer in a seperate middleware and attach it to the above route.
function initMulter(req, res, next) {
multer({
dest: req.app.get('cfg').uploads.dir
});
next();
}
router.post('/uploads', initMulter, function (req, res, next) {
console.log(req.files); process.exit();
});
Also in this case, req.files is undefined.
Is there something really wrong that i am doing or should i start blaming the beer?
Multer is it's own middleware.
You can add it to a route via:
router.post('/uploads', multer({
dest: './my/destination' //req.app.get('cfg').uploads.dir
}), function (req, res, next) {
console.log(req.files);
process.exit();
});
Though you're going to have to find another way to access your config.
One way would be to pass the config or app through an export function.
module.exports = function(config) {
router.post('/uploads', multer({
dest: config.uploads.dir
}), function (req, res, next) {
console.log(req.files);
process.exit();
});
return router;
});
Then when you're requiring,
var route = require('./route')(app.get('cfg'));

Resources