Set multer properties inside an express route - node.js

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'));

Related

Multer middlware in Node.js returns empty object in req.body and undefined in req.file

The problem is when I use multer and send a request in Postman the req.body comes as an empty object and the req.file comes as undefined. I've unchecked the content-type header in postman.
And here's the code:
//Route
const storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, '../uploads/');
},
filename: function (req, file, cb) {
cb(null, new Date().toISOString() + file.originalname);
}
});
const upload = multer({
storage,
limits: {fileSize: 1024 * 1024 * 10}
});
router.post('/test', upload.single('profilePicture'), authController.test);
//Controller
const test = (req, res) => {
console.log(req.body)
console.log(req.files)
res.json({body:req.body, files:req.files})
}
//app.js
app.use(express.json({extended: true, limit: '30mb'}));
app.use(express.urlencoded({extended: true, limit: '30mb'}))
app.use(cookieParser());
app.use('/api/auth', authRoutes);
app.use('/api/product', productRoutes);
app.use('/api/profile', profileRoutes);
Edit: turnes out, the problem is in Postman. I made a request with axios from a React app and everything works. So the question is, why doesn't it work in Postman? Is it some Bug in software or is there some settings that we're supposed to change?
The problem is that Nodejs is by default uses Ansynchornus Javascript. You need to use the async-await approach and try-catch-finally methods over conventional JS programming.
So your controller would look like -
//Route
router.post('/test', async (req, res, next)=>
{
try{
await upload.single('profilePicture')
next()
} catch(err){
console.log(err)
res.send('failed!')
},
authController.test);
//Controller
const test = async (req, res) => {
try{
console.log(req.body)
console.log(req.files)
res.json({body:req.body, files:req.files})
} catch(err){
console.log(err);
}
}
A late addition to the answer.
If you're trying to just access the uploaded image, then you should make use of the buffer.
var storage = multer.memoryStorage()
var upload = multer({ storage: storage })

How to run auth check in my express route before uploading a file with multer

Working on my backend in node.js and express, newly using multer to upload a file.
I want to check if my user has a valid token: If yes he can upload a file, if not, get a 401 back. With my following code, this works, but the file still gets uploaded, even if the user has no valid token.
I guess my check should happen before the parameter upload.single('image'), but I don't really know how. Any tips?
My code:
router.post("/", upload.single('image'), (req, res, next) => {
if (!req.isAuth) {
res.status(401).json({error: "Unauthenticated"});
} else {
console.log('file', req.file);
res.status(200).json({resultFileName: req.file.filename });
}
});
Create a middlewares or helper and create authorize.js file in it and add jwt auth code in it like below
authorize.js
const jwt = require('jsonwebtoken');
module.exports = {
jwtAuth: (req, res, next) => {
//Jwt verification code according to your configuration
}
}
And import that file in your route folder and use it like below
Users.js
const authorize = require('../middlewares/authorize')
router.post("/", authorize.jwtAuth, upload.single('image'), (req, res, next) => {
console.log('file', req.file);
res.status(200).json({resultFileName: req.file.filename });
});
You can try this but i haven't tested it and haven't used express in a while.
router.post("/", (req, res, next) => {
if (!req.isAuth)
return res.status(401).json({error: "Unauthenticated"});
next();
}, upload.single('image'), (req, res, next) => {
console.log('file', req.file);
res.status(200).json({resultFileName: req.file.filename });
});

Node.js Custom Middleware Using An Object Of Functions

In Express.js, ihave been having problems with making my own middleware. I know that middleware is supposed to be a function, but can the middleware function be inside an array.
For Example:
module.js:
module.exports = {
function1: function(req, res) {
console.log('function1');
//second edit.
I want to return something as well
return 'hello world';
//if i add next(); it wont call the next();
},
function2: function(req, res) {
console.log('function2');
}
}
app.js:
const express = require('express')
, middleware = require('./module')
, app = express();
app.use(middleware.function1);
app.use(middleware.function2);
app.get('/', (req, res) => {
//this is an edit: i want to use some code here like
res.send('Hello World');
middleware.function1();
});
app.listen(8080);
When i Do This, the webpage just doesn't load. Any Help?
You are missing crucial part next function (which is callback to trigger next middleware in the sequence) in defining middleware functions function1 and function2.
Have you seen https://expressjs.com/en/guide/writing-middleware.html ?
In below code, you are not passing req, res to the middleware function.
app.get('/', (req, res) => {
middleware.function1();
});
OR call it directly as below
app.get('/', middleware.function1);

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();
}

Dynamically reload multer with new limits fileSize value

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');
});
});

Resources