I was able to move a very simple middleware (isAuthenticated) over to an external middleware file, but I'm having a harder time with moving my multer upload over. I just learned how to move them to seperate files, so it's probably obvius.
routes/index.js
var middleware = require('../middleware/common');
var isAuthenticated = middleware.isAuthenticated;
var upload = middleware.multerSetup;
...
router.post('/updateuser',
upload,
...,
function (req, res, next) {
res.redirect('/dashboard');
}
);
--
//middleware/common.js
var multer = require('multer');
Middleware = {
//Checks whether user is logged in
isAuthenticated: function(req,res,next){
if(req.isAuthenticated()){
return next();
}
req.flash('auth',"You do not have the proper permissions to access this page");
res.redirect('/');
},
multerSetup: function(req,res,next){
var storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, './public/uploads/')
},
//detects file type, then adds extension to match file type
filename: function (req, file, cb) {
var ext = "";
switch(file.mimetype){
case 'image/png':
ext = '.png';
break;
case 'image/jpeg':
ext = '.jpeg';
break;
default:
ext = '';
}
cb(null, Date.now() + ext); //Appending .jpg
}
});
var upload = multer({storage:storage, fileFilter: function (req, file, cb) {
var acceptedExt = ['.png','.jpg','.gif','.bmp'];
if (req.hasOwnProperty('file') && acceptedExt.indexOf(path.extname(file.originalname))=== -1) {
return cb(new Error('Image type not allowed: ' + path.extname(file.originalname)));
}
cb(null, true)
}});
return upload.single('upl');
}
};
module.exports = Middleware;
Error:
routes\index.js:108
upload.single('upl'),
^
TypeError: upload.single is not a function
at Object.<anonymous> (C:\Users\Tyler\WebstormProjects\volunteer\volunteerApp\routes\index.js:108:12)
You're setting up your multer middleware wrong. Your Middleware.multerSetup is a middleware function, which is then calling upload.single to set up multer (which is then never called and the request is left hanging). Move your multer upload setup outside your custom middleware and have your module export just the return function from upload.single.
Example:
Middleware = {
...
multerSetup: upload.single('upl')
...
}
Got it! Just needed to define upload in routes/index.js as a function.
var upload = middleware.multerSetup();
Brother in the separate file, declare your setup function, then your middleware and export it, and pass the "file" as a parameter in upload function and return upload.single(file):
const multer = require("multer");
function multerSetup() {
const storage = multer.diskStorage({
destination: (req, file, cb) => {
cb(null, "images");
},
filename: (req, file, cb) => {
cb(null, file.originalname);
},
});
return storage;
}
Middleware = {
upload: function (file) {
const upload = multer({ storage: multerSetup() });
return upload.single(file);
},
};
module.exports = Middleware;
In your route file write your route:
const router = require("express").Router();
const Middleware = require("../helper/uploadImages");
router.post("/", Middleware.upload("file"), (req, res) => {
res.status(200).json("file has been uploaded!");
});
module.exports = router
in index.js file just you need to import your route and use it:
const uploadImageRoute = require("./routes/uploadImages");
app.use("/api/upload", uploadImageRoute);
Related
I am using Multer Node JS package to upload files to my app sever , the code is basically typical upload file code
const express = require('express')
const multer = require('multer')
const upload = multer({ dest: 'uploads/' })
const app = express()
app.post('/profile', upload.single('avatar'), function (req, res, next) {
// req.file is the `avatar` file
// req.body will hold the text fields, if there were any
})
app.post('/photos/upload', upload.array('photos', 12), function (req, res, next) {
// req.files is array of `photos` files
// req.body will contain the text fields, if there were any
})
But each time a file is being uploaded the Node server becomes unresponsive and frontend from other request doesnt receive any response from other APIs until the file is uploaded.
Whats the best way to tackle this ?
In your sample code, you must just send a response to the client by res.json() or res.end() :
const express = require('express');
const multer = require('multer');
const upload = multer({ dest: 'uploads/' });
const app = express();
app.post('/profile', upload.single('avatar'), function (req, res, next) {
// req.file is the `avatar` file
// req.body will hold the text fields, if there were any
res.status(204).end();
});
app.post('/photos/upload', upload.array('photos', 12), function (req, res, next) {
// req.files is array of `photos` files
// req.body will contain the text fields, if there were any
res.status(204).end();
});
i can give you an example of how i implemented an imageupload in my app. it the code to upload a profile image for a user. i am also using multer middleware so it shoulder be similiar for you:
code is as follows:
// multer middleware:
const multer = require('multer');
const MIME_TYPE_MAP = {
'image/png': 'png',
'image/jpeg': 'jpg',
'image/jpg': 'jpg',
};
module.exports = storage = multer.diskStorage({
destination: (req, file, cb) => {
const isValid = MIME_TYPE_MAP[file.mimetype];
let error = new Error('invalid mime type');
if (isValid) {
error = null;
}
cb(error, 'images');
},
filename: (req, file, cb) => {
const name = file.originalname.toLowerCase().split(' ').join('-');
const ext = MIME_TYPE_MAP[file.mimetype];
if (name.includes('.' + ext)) {
cb(null, name)
} else {
cb(null, name + '.' + ext);
}
},
});
and here the code in the service handling the fileupload
// profile service in backend written in express
exports.uploadImage = (req, res, next) => {
const url = req.protocol + '://' + req.get('host');
profileRepository
.findOne({ _id: req.params.id })
.then((response) => {
const fetchedUser = response;
fetchedUser.imagePath = url + '/images/' + req.file.filename;
profileRepository
.updateOne({ _id: req.params.id }, fetchedUser)
.then((response) => {
return res.status(200).json({
message: 'profileimage updated',
});
})
.catch((error) => {
return res.status(500).json({
message: 'uploading image failed',
});
});
})
.catch((error) => {
return res.status(404).json({
message: 'fetching user failed',
});
});
};
then i use the middleware in my profile routes file like this:
// profile.routes.js
const express = require('express');
const ProfileController = require('./profileController');
const checkAuth = require('../middleware/checkAuth');
const router = express.Router();
const fileStorage = require('../middleware/fileStorage');
const multer = require('multer');
// imageUpload
router.post('/user/image/:id', checkAuth, multer({storage: fileStorage}).single('image'), ProfileController.image);
my Controller then calls the service function with the actual business logic like this:
// profile.controller.js
const profileService = require('./profileService');
exports.image = (req, res, next) => {
return profileService.uploadImage(req, res);
};
and finally my route is used by my app.js file like this:
// app.js
const express = require('express');
const profileRoutes = require('./profile/profileRoutes');
const app = express();
// set images path for saving images on server
app.use('/images', express.static(path.join('images')));
app.use('/api', profileRoutes);
module.exports = app;
i hope i was able to point you in the right direction with my example
I am trying to upload different types of files to server using multer in an express application. But every time server responds by stating TypeError: req.files is not iterable . I checked and req.files is empty.
Here is the code for the same:
var express = require('express');
var app = express();
var multer = require('multer');
var storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, 'uploads/')
},
filename: function (req, file, cb) {
cb(null, Date.now() + '-' + file.originalname)
}
})
var upload = multer({ storage: storage }).array('userfiles', 10);
app.post('/upload', function (req, res) {
upload(req, res, function (err) {
if (err instanceof multer.MulterError) {
// A Multer error occurred when uploading.
return res.status(500).json(err);
} else if (err) {
// An unknown error occurred when uploading.
return res.status(500).json(err);
}
let uploadedFiles = [];
for (let item of req.files) {
uploadedFiles.push({ filename: item.originalname });
}
// Everything went fine.
res.json({ progress: 100, files: uploadedFiles });
})
});
app.listen(8000, (err) => {
if (err) {
console.log('ERROR:', err);
} else {
console.log('working on http://localhost:8000');
}
})
And this is how I am calling this API from postman:
Postman UI
I am unable to figure out where the problem is. Please help me with this.
I ran his code and he tried to store the images at the root of my filesystem.
to refer a a path relative to your current directory you need to use ./
var storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, 'uploads/') // change 'upload/' to './uṕload'
},
filename: function (req, file, cb) {
cb(null, Date.now() + '-' + file.originalname)
}
})
After this, the code worked.
I want to export modul multer to another file but the console returns an error to me.
TypeError: uploadImg.single is not a function
here is my multer.js
module.export = () => {
const multer = require("multer");
const storage = multer.diskStorage({
destination(req, file, cb) {
const url = `./uploads/catalog`;
cb(null, url);
},
filename(req, file, cb) {
file.originalname = "re_" + file.originalname;
cb(null, `${file.originalname}`);
}
});
const uploadImg = multer({
storage: storage
});
return uploadImg;
};
And here is a part of my routes file
const uploadImg = require("./../services/multer");
app.post("/catalog/upload/img", uploadImg.single("image"), async (req, res, next) => {
console.log(req.file);
});
You start with this: module.export = () => {... which means that you export the function.
So uploadImg is the function const uploadImg = require("./../services/multer"); and the only way how to call it is with uploadImg().
If you have everything else correct then uploadImg().single("image") should do the trick, but then it does not make sense to export it as function. If you use it in static context (which routes are), then you probably want something like this:
const multer = require("multer");
const storage = multer.diskStorage({
destination(req, file, cb) {
const url = `./uploads/catalog`;
cb(null, url);
},
filename(req, file, cb) {
file.originalname = "re_" + file.originalname;
cb(null, `${file.originalname}`);
}
});
const uploadImg = multer({
storage: storage
});
exports.uploadImg = uploadImg;
Then you can call it as following
const myMulter = require("./../services/multer");
app.post("/catalog/upload/img", myMulter.uploadImg.single("image"), async (req, res, next) => {
console.log(req.file);
});
You have a typo in multer.js
You should write module.exports = instead of module.export =
I use to upload files a multer library with feathers. I try to separate logic from code and I want put upload code not in a index.js but in my case in pdf.js in middleware directory.
Below is my works index.js:
'use strict';
const pdf = require('./pdf');
const record = require('./record');
const records = require('./records');
const handler = require('feathers-errors/handler');
const notFound = require('./not-found-handler');
const logger = require('./logger');
const uploadPdf = require('./upload-pdf');
module.exports = function() {
// Add your custom middleware here. Remember, that
// just like Express the order matters, so error
// handling middleware should go last.
const app = this;
app.use('/rekord/:id.html', record(app));
app.use('/rekordy.html', records(app));
app.use('/pdf/:id', uploadPdf.single('file'), pdf(app));
app.use(notFound());
app.use(logger(app));
app.use(handler());
};
Here is upload-pdf.js file:
var multer = require('multer')
var storagePdf = multer.diskStorage({
destination: 'public/pdf',
filename: function (req, file, cb) {
var id = req.params.id
cb(null, id+'.pdf')
}
});
module.exports = multer({
storage: storagePdf,
fileFilter: function (req, file, cb) {
if (file.mimetype !== 'application/pdf') {
return cb(null, false, new Error('I don\'t have a clue!'));
}
cb(null, true);
}
});
And pdf.js file:
'use strict';
module.exports = function(app) {
return function(req, res, next) {
if (req.file) {
return res.end('Thank you for the file');
}
return res.end('false');
next();
};
};
I would like to combine upload-pdf.js and pdf.js into one file
Not particularly Feathers specific, just as with any other Express application you can put the code into their own modules:
'use strict';
const pdf = require('./pdf');
const record = require('./record');
const records = require('./records');
const handler = require('feathers-errors/handler');
const notFound = require('./not-found-handler');
const logger = require('./logger');
module.exports = function() {
// Add your custom middleware here. Remember, that
// just like Express the order matters, so error
// handling middleware should go last.
const app = this;
app.use('/rekord/:id.html', record(app));
app.use('/rekordy.html', records(app));
app.use('/pdf/:id', pdf.upload.single('file'), pdf.process(app));
app.use(notFound());
app.use(logger(app));
app.use(handler());
};
In pdf.js:
'use strict';
var multer = require('multer')
var storagePdf = multer.diskStorage({
destination: 'public/pdf',
filename: function(req, file, cb) {
var id = req.params.id
cb(null, id + '.pdf')
}
});
exports.upload = multer({
storage: storagePdf,
fileFilter: function(req, file, cb) {
if (file.mimetype !== 'application/pdf') {
return cb(null, false, new Error('I don\'t have a clue!'));
}
cb(null, true);
}
});
exports.process = function(app) {
return function(req, res, next) {
if (req.file) {
return res.end('Thank you for the file');
}
return res.end('false');
next();
};
};
The NodeJS module system docs are quite helpful to learn how it all fits together.
routes.js
module.exports=function(app, upload){
var postingsController=require('../controllers/postings.server.controller');
app.post('/postings', postingsController.savePosting);
}
controller.js
var multer=require('multer');
exports.savePosting=function(req, res, next){
// this diskstorage function is not at all executed
var storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, './uploads')
},
filename: function (req, file, cb) {
console.log(file);
cb(null, file.filename + '.' + 'jpg');
}
});
var upload = multer({ storage: storage });
upload.single('attachment');
res.json({ message: "success" });
}
can someone tell me which line exactly uploads file. DO i write multer diskstorage configuration in main express configuration file or can i write any where. By the way i able to see json response which is from the line
Typically the middleware is created and inserted outside of any actual route handlers. For example:
routes.js
var multer = require('multer');
var storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, './uploads')
},
filename: function (req, file, cb) {
console.log(file);
cb(null, file.filename + '.' + 'jpg');
}
});
var upload = multer({ storage: storage });
module.exports = function(app, upload) {
var postingsController = require('../controllers/postings.server.controller');
app.post('/postings',
upload.single('attachment'),
postingsController.savePosting);
};
controller.js
exports.savePosting = function(req, res, next) {
// Use `req.file` to access attachment
if (req.file)
res.json({ message: "success" });
else // no file uploaded
res.json({ message: "failure" });
};
Multer is a middleware, which means it is added as a parameter to your route in most cases. So what the actual syntax would be like is:
app.post ("/postings", multer ({ ... }), postingsController.savePosting);
Multer gets called inbetween the request to "/postings" and the final function to do all the file work for you. It will then provide you with all the information via
req.files["fileInputName"]
in the following middlewares (your function is a "middleware", too).