Handling errors in multer? - javascript

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

Related

Multer next() funtion not a funtion

I'm developing this server based on this tutorial, https://www.bezkoder.com/angular-12-node-js-express-mysql/ now I'm in need of add some file upload functionalities, using Multer. but each time I try to us it, I get this error:
/home/miguel/Documents/angular_projs/examples/server/node_modules/multer/lib/make-middleware.js:45
next(err)
^
TypeError: next is not a function
at done (/home/miguel/Documents/angular_projs/examples/server/node_modules/multer/lib/make-middleware.js:45:7)
when i use it here:
//File upload configuration
const maxSize = 2 * 1024 * 1024;
let storage = multer.diskStorage({
destination: (req, file, cb) => {
cb(null, "/resources/static/assets/uploads/");
},
filename: (req, file, cb) => {
console.log(file.originalname);
cb(null, file.originalname);
},
});
let uploadFile = multer({
storage: storage,
limits: { fileSize: maxSize },
}).single("file");
/* ---------------------------------------------------------------------------------------------------- */
//Upload Files
exports.file_upload = async (req, res) => {
let number = req.params.number;
try {
await uploadFile(req, res);
if (req.file == undefined) {
return res.status(400).send({ message: "Please upload a file!" });
}
res.status(200).send({
message: "Uploaded the file successfully: " + req.file.originalname,
});
} catch (err) {
if (err.code == "LIMIT_FILE_SIZE") {
return res.status(500).send({
message: "File size cannot be larger than 2MB!",
});
}
res.status(500).send({
message: `Could not upload the file: ${req.file.originalname}. ${err}`,
});
}
//Check if empty
//res.status(200).json({msg:`${s03}`});
};
I've checked other tutorial and it's suppose to work
Try passing in next as a parameter.
...
exports.file_upload = async (req, res, next) => {
let number = req.params.number;
try {
await uploadFile(req, res, next);
...

How to get info from an object with multer

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

Express.js application error: Cannot read properties of undefined (reading 'transfer-encoding'

I am working on a blogging app API with express and MongoDB.
I am trying to add a post image for every blog post. Being new to express, I ran into this problem.
And i got this error:
Cannot read properties of undefined (reading 'transfer-encoding'
Here is the post controller code code:
const asyncHandler = require("express-async-handler");
const imageModel = require("../models/imageModel");
const User = require("../models/userModel");
const Post = require("../models/postModel");
// storage
const Storage = multer.diskStorage({
destination: "storage",
filename: (res, req, file, cb) => {
cb(null, Date.now() + file.originalname);
},
});
const upload = multer({
storage: Storage,
}).single("img");
// #desc Create a new post
// #route POST /api/posts/
// #access Private
const createPost = asyncHandler(async (res, req) => {
let img;
upload(req, res, async function (err) {
if (err) {
res.status(400);
throw new Error("Error uploading images.");
}
const newImage = await new imageModel({
img: {
data: req.file.filename,
contentType: "image/png",
},
});
newImage.save().then(console.log("Successfully uploaded"));
img = newImage;
});
console.log(img);
const { title, description, categories, nacCompatible, downloadURL } =
req.body;
if (!title || !description || !categories || !downloadURL) {
res.status(400);
throw new Error("Please add all the required fields.");
}
// Get user using the id in the JWT
const user = await User.findById(req.user.id);
if (!user) {
res.status(401);
throw new Error("User not found");
}
const post = await Post.create({
title,
description,
img,
categories,
nacCompatible,
downloadURL,
user: req.user._id,
status: "new",
});
res.status(201).json(post);
});
I also have const multer = require("multer"); at the top of the controller.
The create post function worked fine until I tried to add this upload image feature.
This line: "createPost = asyncHandler(async (res, req)"
You put the req and res in the wrong order

Get image path with Multer Express Nodejs

I am using Multer to save images but I need to get the path of the image to save it to MongoDB. I am trying to get the path with req.file but it always tells me on the console that it is undefined.
this is my route:
import { Router } from 'express';
import { check, validationResult } from 'express-validator';
const multer = require('multer');
const storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, 'uploads/products')
},
filename: function (req, file, cb) {
cb(null, new Date().toISOString().replace(/:/g, '-') + file.originalname)
}
});
const fileFilter = (req, file, cb) => {
// reject a file
if (file.mimetype === 'image/jpeg' ||file.mimetype === 'image/png') {
cb(null, true);
} else {
cb(null, false);
//cb(new Error('I don\'t have a clue!'))
}
}
const upload = multer(
{ storage: storage,
limits:{
fileSize: 1024 * 1024
},
fileFilter: fileFilter
});
let router = Router();
router.post('/', upload.single('img'),
newProduct
);
And in the new Product controller I am trying to read the req.file but the console tells me that it is undefined:
Controller:
import { Product } from '../models'
let newProduct = async (req, res = response ) => {
console.log('file ' + req.file); //UNDEFINED
try {
let { status, user, ...body } = req.body;
let productDB = await Product.findOne ( { 'name': body.name } );
if (productDB) {
return res.status(400).json({
msg:`El producto ${ productDB.name } ya existe`
})
}
let data = {
...body,
name: body.name,
user: req.user._id
}
let product = new Product( data );
await product.save();
res.status(200).json( product );
} catch (error) {
return res.status(400).json({
error
});
}
}
Console:
Thanks for your help.
you can try to do this in filename instead:
filename: function (req, file, cb) {
req.imageName = new Date().toISOString().replace(/:/g, '-') + file.originalname
cb(null, req.imageName)
}
then there:
console.log('file ' + req.file); //UNDEFINED
//you can get imageName instead
console.log('imageName',req.imageName)
//if you want url to store in database you can do this
//supposing your have images directory in root of your node server
const url = `${req.protocol}://${req.get('host')}/images/${req.body.image}`

How do I upload FIle in Vuejs and Expressjs

Hey please am new to Vuejs and Express...So am trying to practice.
So am trying to create a User Profile with comes with a image Using Vuejs and ExpressJs but none of the file or text is uploading.
This is my CreateProfile.vue file
<div class="icon-pic">
<label for="Password">Upload your Logo / Picture</label>
<input type="file" ref="file" #change="handleFileUpload"/>
</div>
<b-input-group class="mb-2">
<b-form-input
id="input-small"
type="text"
placeholder="Enter your Name"
required
:rules="[rules.required]"
v-model="profile.fullname"
></b-form-input>
<b-form-input
id="input-small"
type="text"
placeholder="Enter your BrandName"
v-model="profile.brandname"
></b-form-input>
</b-input-group>
Note: There are other inputs...
Below is my script functions for the form
<script>
import ProfileService from '#/services/ProfileService'
export default {
data () {
return {
profile: {
fullname: null,
brandname: null,
skill1: null,
skill2: null,
skill3: null,
skill4: null,
socail_handle1: null,
socail_handle2: null
},
file: null,
error: null,
rules: {
required: (value) => !!value || 'Required.'
}
}},
methods: {
handleFileUpload () {
const file = this.$refs.file.files[0]
this.file = file
},
async create () {
this.error = null
const formData = new FormData()
formData.append('file', this.files)
const areAllFieldsFilledIn = Object.keys(this.profile).every(
(key) => !!this.profile[key]
)
if (!areAllFieldsFilledIn) {
this.error = 'Please fill in all the required fields.'
return
}
try {
await ProfileService.post(this.profile, formData)
this.$router.push({
name: 'profile'
})
} catch (error) {
this.error = error.response.data.error
}
}}}
Below is my ProfileController.js file
const {Profile} = require ('../models')
const multer = require ('multer')
const fileFilter = (req, file, cb) => {
const allowedTypes = ["image/jpeg", "image/jpg", "image/png"]
if (!allowedTypes.includes(file.mimetype)){
const err = new Error('Incorrect File');
return cb(err, false)
}
cb(null, true)
}
const upload = multer ({
dest: '../public',
fileFilter,
})
module.exports = {
async post (req, res){
try {
upload.single('files')
const profile = await new Profile({
profile: this.profile,
files: req.file
});
profile.save().then(result => {
console.log(result);
res.status(201).json({
message: "Done upload!"
})
})
} catch (err) {
console.log(err)
res.status(500).send({
error: 'An Error has occured trying to fetch'
})}}
Follow by my Model/Profile.js file
module.exports = (sequelize, DataTypes) => {
const Profile = sequelize.define('Profile', {
files: {
type: DataTypes.JSON
},
fullname: {
type: DataTypes.STRING,
allowNull: false
},
brandname: DataTypes.STRING,
skill1: DataTypes.STRING,
skill2: DataTypes.STRING,
skill3: DataTypes.STRING,
skill4: DataTypes.STRING,
socail_handle1: DataTypes.STRING,
socail_handle2: DataTypes.STRING
})
return Profile
}
I hope any one can help me with this please!!!
This is my route.js file
const AuthController = require('./controllers/AuthController')
const AuthControllerPolicy = require('./policies/AuthControllerPolicy')
const ProfileControler = require('./controllers/ProfileController')
const upload = require ('multer')
module.exports = (app) => {
app.post('/register',
AuthControllerPolicy.register,
AuthController.register)
app.post('/login',
AuthController.login)
app.get('/profile',
ProfileControler.index)
app.post('/upload', upload.single('file'),
ProfileControler.upload)
}
I notice two things:
You're not using multer as a middleware function
upload.single('file') returns a function which should be passed as a middleware in your Express routes. You can use it like this in your route.js:
const multer = require('multer');
const upload = multer({
dest: '../public',
fileFilter,
});
app.post('/upload', upload.single('file'), ProfileController.post);
Then you can remove the upload code in your post function:
module.exports.post = async (req, res) => {
// Multer makes your file available at req.file
const file = req.file;
try {
// Don't need to await when creating a new Mongo object
const profile = new Profile({
profile: this.profile,
files: file
});
// Refactored this to use async/await instead of promises.
// Avoid mixing promises with async/await.
const result = await profile.save();
return res.status(201).json({ message: "Done upload!" });
} catch (error) {
console.log(error)
return res.status(500).send({ error: 'An Error has occured trying to fetch' });
}
}
The name of the file input passed to multer doesn't match with frontend
You're configuring multer to look for a file input named files: upload.single('files'), yet in the frontend you're naming it file (singular): formData.append('file', this.files). Usually multer will then throw an unexpected field error. Make sure these two match exactly.
This free guide for Parsing Requests in Node.js will help you handle file uploads in Node.js.

Categories