I need to get the filename info from two files sended with multer, but when I try to send a JSON with the response, it sends a Object: null prototype and the info from the images. But I canĀ“t access to it. What can I do?
Here is my code:
// Multer File
const multer = require("multer");
const path = require("path");
const storage = multer.diskStorage({
destination: (req, file, cb) => {
cb(null, path.join(__dirname, "../../imagesDirectory"));
},
filename: (req, file, cb) => {
cb(
null,
`${req.params.campana}-${req.params.metodo}-${file.fieldname}-${new Date()
.toISOString()
.replace(/:/g, "-")}-${file.originalname}`
);
},
});
const upload = multer({ storage: storage });
const uploads = upload.fields([
{ name: "image1" },
{ name: "image2" },
{ name: "image3" },
{ name: "image4" },
{ name: "image5" },
{ name: "image6" },
{ name: "image7" },
]);
module.exports = uploads;
// Controller
const uploadFile = async (req, res) => {
if (!req.files) {
console.log("You need to add an image");
res.json({ err: "You need to add an image" });
} else {
console.log(req.files);
let name = req.files.filename;
res.json({ msg: "Image Upload", rows: name });
}
};
module.exports = { uploadFile };
Related
i'm trying to upload two files with different file extensions with multer from two fields but when i try it with postman the result always for the file is null, what is the solution for my problem? here is my code
middleware/uploadEpub
const multer = require('multer')
exports.uploadEpub = (epubFile, coverFile) => {
const storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, "uploads")
},
filename: function (req, file, cb) {
cb(null, Date.now() + '-' + file.originalname.replace(/\s/g, ""))
}
})
const upload = multer({
storage
}).fields([{name: "bookFile", maxCount: 1},{name: "coverFile", maxCount: 1}])
}
controller/book
exports.addBook = async (req, res) => {
try {
const { ...data } = req.body
const newBook = await book.create({
...data,
bookFile: req.file,
coverFile: req.file
})
let bookData = await book.findOne({
where: {
id: newBook.id
},
attributes:{
exclude: ['createdAt','updatedAt']
}
})
bookData = JSON.parse(JSON.stringify(bookData))
res.send({
status: "Success",
Book: {
...bookData
}
})
} catch (error) {
console.log(error)
res.status(500).send({
status: "Failed",
message: "Server Error"
})
}
}
Multer set up
const multer = require('multer')
const path = require('path')
const { nanoid } = require('nanoid')
//Set Storage Engine
const storage = multer.diskStorage({
destination: './public/uploads/',
filename: (req, file, callback) => {
const id = nanoid(6)
const newFilename = `${file.fieldname}_${id}-${new Date().toISOString().replace(/:/g, '-')}${path.extname(file.originalname)}`
callback(null, newFilename)
}
})
const upload = multer({
storage: storage,
limits: { fileSize: 5572864 }, // up to 5.5 MB
fileFilter: (req, file, callback) => {
checkFileType(file, callback)
},
})
//Check File Type
const checkFileType = (file, cb) => {
//Allowed extensions
const fileType = /jpeg|jpg|png|gif|svg|pdf|epub/
//Check extension
const extname = fileType.test(path.extname(file.originalname).toLowerCase())
//Check mimetype
const mimetype = fileType.test(file.mimetype)
if (extname && mimetype) {
return cb(null, true)
} else {
return cb('Error: wrong file type!')
}
}
module.exports = upload
/***** middlewares.js *****/
module.exports.imageUploader = (req, res, next)=>{
const files = req.files
const uploadedFiles = []
for (var i = 0; i <images.length; i++){
uploadFiles.push('https://yourserver.com/public/uploads/' + files[i].filename)
}
req.uploadFiles = uploadFiles.toString() //appending files to req
next()
return
}
/**** index.js or app.js ****/ //where your routes are defined
router.post('/books/add', upload.array('images', 10), imageUploader, book.addBook) // allowing up to 10 files to be uploaded, calling imageUploader as a middleware
/*** Controllers/book ***/
exports.addBook = async (req, res) => {
const uploadedFiles = req.uploadFiles; //catching files from imageUploader middleware
// ... rest of your code
}
Try to upload the file as form-data in postman, and put the key with the same name that you have set in multer, the postman will look like this:
Try this:
const cpUpload = upload.fields([{ name: 'avatar', maxCount: 1 }, { name: 'gallery', maxCount: 8 }])
app.post('/cool-profile', cpUpload, function (req, res, next) {
})
For error handling multer suggest
const multer = require('multer')
const upload = multer().single('avatar')
app.post('/profile', function (req, res) {
upload(req, res, function (err) {
if (err instanceof multer.MulterError) {
// A Multer error occurred when uploading.
} else if (err) {
// An unknown error occurred when uploading.
}
// Everything went fine.
})
})
I wrote a custom middleware for uploading different types of file.
const { check } = require("express-validator")
const multer = require('multer')
const mime = require('mime-types')
const storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, 'uploads/')
},
filename: function (req, file, cb) {
const filename = Date.now()+"-"+file.originalname
cb(null, filename)
}
})
const upload = multer({ storage: storage })
const uploadFile = (fieldname,filetypes,fileSize)=>{
return (req,res,next)=>{
let file = upload.single(fieldname)
file(req,res,function(err){
if (err instanceof multer.MulterError) {
req.fileError = {
param: "image",
msg: "Unable to process request"
}
return next()
} else if (filetypes.includes(mime.extension(req.file.mimetype)) === false) {
req.fileError = {
param: "image",
msg: `Only ${filetypes.toString()} allowed`
}
return next()
} else if (req.file.size > fileSize) {
req.fileError = {
param: "image",
msg: `File size should not exceed ${formatBytes(req.file.size)}`
}
return next()
}
})
}
}
course_validator = [
check("name")
.trim()
.isLength({min:3,max:100})
.withMessage("Course name should be between 3 to 100 characters")
]
app.get("/create/post",uploadFile("image",["jpeg","jpg"],122880),(req,res)=>{
const errors = validationResult(req)
if(!errors.isEmpty()){
return res.json({
status: false,
error: req.fileError ? [...errors.array(),req.fileError] : errors.array()
})
}
})
If there is no error then only I need to upload the file to uploads folder. When I upload a other than jpeg or jpg I am getting error with message that Only jpeg,jpg allowed. This is what I need. But the problem is the file is also getting uploaded to uploads folder.
For custom error messages you can go through this controller here I'm checking to file type when uploading an image and in the controller, if there is no file selected at that time I'm sending a custom message with simple if the condition after passing all if image and the products will be saved in DB
exports.postProduct = (req, res, next) => {
const title = req.body.title;
const image = req.file;
const price = req.body.price;
const description = req.body.description;
if (!image) {
return res.status(422).render("admin/add-product", {
pageTitle: "Add Product",
path: "/adminproducts",
hasError: true,
product: {
title: title,
price: price,
description: description,
},
errorMessage: "Atteched file is not an image!!!",
validationErrors: [],
});
}
const imageUrl = image.path;
const product = new Product({
title: title,
imageUrl: imageUrl,
price: price,
description: description,
userId: req.user,
});
product
.save()
.then((results) => {
console.log("Product Created Successfully");
res.redirect("/admin/products");
})
.catch((err) => {
console.log(err);
});
};
I'm learning MEAN stack and have trubles on a files upload. I have a company form:
this.companyForm = this.fb.group({
trucks: this.fb.array([]),
...
});
Trucks field is dynamicly created:
newTruck(): FormGroup {
this.added = false;
return this.fb.group({
...
TLic: new FormControl(null, {
validators: [Validators.required]
}),
Lic: new FormControl(null, {
validators: [Validators.required]
}),
CMRLic: new FormControl(null, {
validators: [Validators.required]
})
})
}
addTruck() {
this.trucks().push(this.newTruck());
}
On save form:
this.authService.createUserStep1(
...
this.companyForm.value.trucks
);
AuthService:
createUserStep1(... trucks: Array<any>) {
const AuthDataStep1: AuthDataStep1 = {
...
trucks: trucks
};
this.http.put(BACKEND_URL + "signupStep1/", AuthDataStep1).subscribe(
() => {
this.authStatusListener.next(true);
this.router.navigate(["auth/signupStep2"]);
},
error => {
this.authStatusListener.next(false);
}
);
}
Nodejs controller where I write to DB:
exports.createUserStep1 = (req, res, next) => {
...
for (i = 0; i < req.body.trucks.length; i++) {
const truck = new Truck({
...
TLic: req.body.trucks[i].file.TLic[0].filename,
Lic: req.body.trucks[i].file.Lic[0].filename,
CMRLic: req.body.trucks[i].file.CMRLic[0].filename,
});
Truck.create(truck);
}
})
}
Middleware for files upload:
const multer = require("multer");
var path = require('path');
const storage = multer.diskStorage({
destination: (req, file, cb) => {
cb(null, "backend/truckdocs");
},
filename: (req, file, cb) => {
const name = file.originalname
.toLowerCase()
.split(" ")
.join("-");
cb(null, name + "-" + Date.now() + "." + path.extname(file.originalname));
}
});
module.exports = multer({ storage: storage }).fields([
{
name: "TLic", maxCount: 1
}, {
name: "Lic", maxCount: 1,
}, {
name: "CMRLic", maxCount: 1
}
]);
and route
const express = require("express");
const UserController = require("../controllers/user");
const extractTruckFiles = require("../middleware/truckfiles");
const checkAuth = require("../middleware/check-auth");
const router = express.Router();
/*App*/
...
router.put("/signupStep1", checkAuth, extractTruckFiles, UserController.createUserStep1);
I want to create x number of trucks in form and for each truck upload 3 files(TLic, Lic, CMRLic).What is the best way to achieve this? I know it needs time for you to get into my code and I'm very thankful in advance.
This is how i did for a ecommerce where i upload 3 photo. I have done it with MVC pattern and i called multer in route file.
const express = require("express")
const multer = require("multer");
const router = express.Router()
const productController = require("../../controller/vendor/product")
const app = express();
const fileStorage = multer.diskStorage({
destination: (req, file, cb) => {
cb(null, "images");
},
filename: (req, file, cb) => {
cb(null, new Date().toISOString().replace(/:/g, '-') + '-' +file.originalname)
}
});
const fileFilter = (req, file, cb) => {
if(file.mimetype === 'image/png' || file.mimetype === 'image/jpg' || file.mimetype === 'image/jpeg') {
cb(null, true)
} else {
cb(null, false)
}
}
let filehandler = app.use(multer({storage : fileStorage, fileFilter: fileFilter }).array('image',3))
/* #GET product Page request */
router.get('/products', productController.getProduct)
/* #GET add product page Request */
router.get('/add-product', productController.getAddProduct)
/* #POST Request */
router.post('/add-product', filehandler, productController.postAddProduct)
/* #GET AJAX Request findind subcategory */
router.get("/getSubCategory/:id", productController.getSubCategory);
module.exports = router
I'm hung up on this issue using the multer library on my Node server. I'm trying to upload a file or files and then make a call to the database for each file and then send back success or failure to the client.
So my Node server route for uploading the file(s) looks like this:
app.post('/uploadFiles', (req, res) => {
upload(req, res, async function (err) {
...
Then that upload function is simply this:
const upload = multer({ storage: multerStorage }).array('file');
And then the multerStorage function that handles the destination and filename for multer:
const multerStorage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, process.env.LABELS_LOCATION);
},
filename: async function (req, file, cb) {
// save file info to DB
const itemID = file.originalname.slice(0, -4);
const addLabelResult = addLabelToDB(itemID, 0);
// console.log({ addLabelResult });
// console.log({ itemID });
// console.log({ file });
cb(null, file.originalname);
},
});
And finally the addLabelToDB function:
const addLabelToDB = (itemID, enterType) => {
const sp = 'insertLabelHistory';
const inputs = [
{ name: 'itemID', type: sql.NVarChar, value: itemID },
{ name: 'enterType', type: sql.Bit, value: enterType },
];
return executeSP(res, sp, inputs);
};
So the issue is that, if you look at the addLabelToDB function, you can see the call to executeSP takes in a res. And I want that res from the original /uploadFiles route. But I don't know how to access it from here. And if there a better completely different way to do this, I am all ears.
Maybe you already solved your issue but for future people with the same issue here it goes:
Remember that you can access res from req by req.res
In your case you can just pass res to addLabelToDB, here's how:
const multerStorage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, process.env.LABELS_LOCATION);
},
filename: async function (req, file, cb) {
// save file info to DB
const itemID = file.originalname.slice(0, -4);
const addLabelResult = addLabelToDB(req.res, itemID, 0);
cb(null, file.originalname);
},
});
And then on your addLabelToDB:
const addLabelToDB = (res, itemID, enterType) => {
const sp = 'insertLabelHistory';
const inputs = [
{ name: 'itemID', type: sql.NVarChar, value: itemID },
{ name: 'enterType', type: sql.Bit, value: enterType },
];
return executeSP(res, sp, inputs);
};
I setup multer like this
let multer = require('multer');
let apiRoutes = express.Router();
let UPLOAD_PATH = '../uploads';
let storage = multer.diskStorage({
destination: (req, file, cb) => {
cb(null, UPLOAD_PATH);
},
filename: (req, file, cb) => {
cb(null, file.fieldname + '-' + Date.now());
}
});
let upload = multer({ storage: storage });
and in route I am getting data and an image and use multer like!
apiRoutes.post('/update', passport.authenticate('jwt', { session: false }), (request, response) => {
let record = {
name: request.body.name,
location: request.body.location,
about: request.body.about,
userid: request.body.userid,
avatar: request.body.filename
};
let userData = {
name: request.body.name
};
if (request.body.filename) {
upload(request, response, (error) => {
});
}
profile.findOneAndUpdate({ userid: request.body.userid }, record, {new: true}, (error, doc) => {
if (error) response.json(error);
user.findOneAndUpdate({ _id: request.body.userid }, record, (error, result) => {
if (error) throw error;
response.json(doc);
});
});
});
What is happening with this code is that when I do not send an image to backend then I get data from front end and store it into database. But when I send image along side data then it return POST /api/1.0/profile/update 401 0.396 ms - -.
It means I am not getting any data at all. Whats wring with the code here?
You can't use Multer in your /update route. Use Multer in your router like this:
var upload = multer({ dest: 'uploads/' })
apiRoutes.post('/profile', upload.single('image'), function (req, res, next) {
// Uploaaded
})
if you add it and still can't get our file, you should update your form with this parameter: enctype="multipart/form-data"