I am new in Node js API and I'm trying to upload an Image using multer + express + mongoose + postman
CODE:
var storage = multer.diskStorage({
destination: function (request, file, callback) {
callback(null, 'public/images/course');
},
filename: function (request, file, callback) {
return callback(null, file.originalname)
}
});
var upload = multer({storage : storage})
router.post('/course', upload.single('thumbnail'),async(req, res) => {
try{
var course = new Course({
name : req.body.name,
thumbnail : "placeholder" // set to path where file is uploaded
})
await course.save()
res.status(201).send(course)
}catch(e){
res.status(400).send(e)
}
})
I use postman to post request using form data and it creates an image with its originalFilename but i want the filename to be id generated by mongoose and i have seen somewhere that i can use filesystem for that but is there any way i can upload file after id is generated because when i do like this
var storage = multer.diskStorage({
destination: function (request, file, callback) {
callback(null, 'public/images/course');
},
filename: function (request, file, callback) {
if (request.data) {
console.log(file)
// TODO: consider adding file type extension
fileExtension = file.originalname.split('.')[1]
return callback(null, `${request.path}-${request.data._id.toString()}.${fileExtension}`);
}
// fallback to the original name if you don't have a book attached to the request yet.
return callback(null, file.originalname)
}
});
var upload = multer({storage : storage}).single('thumbnail')
router.post('/course',(req, res) => {
console.log(req.body)
const course = new Course({
name : req.body.name,
thumbnail : req.body.name
})
//console.log(course)
req.data = course
//console.log(req.file)
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.
})
})
Then i got request body empty.
Thanks in advance
Related
So i'm building a marketplace mobile app using, expo that let users upload products to the marketplace. I'm having difficult times using the expo FileSystem.FileSystemUploadType(https://docs.expo.dev/versions/latest/sdk/filesystem/#filesystemfilesystemsessiontype) to pick the image and send to the backend.
here's my front-end code
const handleSubmit = async (listing, { resetForm }) => {
const data = new FormData();
data.append("images", listing.images[0]);
data.append("description", "Good product");
console.log( listing.images[0])
// it does console the file uri
// file:///Users/zakisb/Library/Developer/CoreSimulator/Devices/83E12EA5-E8FA-4850-82C1-84021B25450D/data/Containers/Data/Application/6873BF40-26E4-4BD3-834D-F6772448C004/Library/Caches/ExponentExperienceData/%2540anonymous%252Flokazz_app2-5f4724db-b9d7-45aa-a8ca-ac5acf2f4780/ImagePicker/B72CF40C-EC27-430E-B1F8-B983C0ACF2FB.jpg
// i tried this solution first and worked perfectly. but it does upload the image only and i want to send the formdata object
const response = await FileSystem.uploadAsync(
"http://192.168.43.8:5000/products/addProduct",
listing.images[0],
{
fieldName: "images",
uploadType: FileSystem.FileSystemUploadType.MULTIPART,
}
);
// so i tried this but i get an error
const response = await FileSystem.FileSystemUploadType.MULTIPART(
"http://192.168.43.8:5000/products/addProduct",
data
);
};
My backend works perfectly. i tried the api call using insomnia and postman the file gets uploaded successfully to the folder. but using expo methods i get nothing.
const storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, "./images");
},
filename: function (req, file, cb) {
cb(null, Date.now() + file.originalname);
},
router.post(
"/products/addProduct",
upload.single("images"),
async (req, res) => {
console.log(req.body);
try {
res.send(req.body);
} catch (err) {
res.send("Error " + err);
}
}
);
});
I am trying to upload an image from my front end to the backend but it it doesn't send the image in the request
It says that the formdata is empty and it says that there's no image found, where is the problem and how can I fix this error?
Here is the code from the Frontend made in react:
const [userInfo, setuserInfo] = useState({
file:[],
filepreview:null,
});
const handleInputChange = (event) => {
setuserInfo({
...userInfo,
file:event.target.files[0],
filepreview:URL.createObjectURL(event.target.files[0]),
});
}
const [isSucces, setSuccess] = useState(null);
const submit = async () =>{
const formdata = new FormData();
formdata.append('avatar', userInfo.file);
console.log(formdata)
Axios.post("http://localhost:4000/imageupload", formdata,{
headers: { "Content-Type": "multipart/form-data" }
})
.then(res => { // then print response status
console.warn(res);
if(res.data.success === 1){
setSuccess("Image upload successfully");
}
})
}
The code of the Backend made in NodeJS:
const storage = multer.diskStorage({
destination: path.join(__dirname, './temp', 'uploads'),
filename: function (req, file, cb) {
// null as first argument means no error
cb(null, Date.now() + '-' + file.originalname )
}
})
app.post('/imageupload', async (req, res) => {
try {
// 'avatar' is the name of our file input field in the HTML form
let upload = multer({ storage: storage}).single('avatar');
upload(req, res, function(err) {
// req.file contains information of uploaded file
// req.body contains information of text fields
if (!req.file) {
return res.send('Please select an image to upload');
}
else if (err instanceof multer.MulterError) {
return res.send(err);
}
else if (err) {
return res.send(err);
}
const classifiedsadd = {
image: req.file.filename
};
res.send("ok")
});
}catch (err) {console.log(err)}
})
Edit:
Multer is essentially a nodejs router,i.e. a function that can be pipelined between your HTTP request and HTTP response.
I think that you should first make multer analyze your HTTP content and to actually populate the req.file before actually evaluate express parsers do their job.
const storage = multer.diskStorage({
destination: path.join(__dirname, './temp', 'uploads'),
filename: function (req, file, cb) {
// null as first argument means no error
cb(null, Date.now() + '-' + file.originalname )
}
})
let upload = multer({ storage: storage});
app.post('/imageupload', upload.single('avatar'), async (req, res) => {
try {
// 'avatar' is the name of our file input field in the HTML form
// req.file contains information of uploaded file
// req.body contains information of text fields
if (!req.file) {
return res.send('Please select an image to upload');
}
else if (err instanceof multer.MulterError) {
return res.send(err);
}
else if (err) {
return res.send(err);
}
const classifiedsadd = {
image: req.file.filename
};
res.send("ok")
}catch (err) {console.log(err)}
})
I am assuming that your upload code is working. Have you tried to read the HTTP request from your browser to see that the image has been correctly attached to the request?
Because probably the issue lies in the fact that you are not actually parsing the image.
const file = new File(userInfo.file, "avatar.png", {
type: 'image/png' // choose the appropriate
});
const formdata = new FormData();
formdata.append('avatar', file);
console.log(formdata)
I am giving post request /product/create with some value and an image.
if I console every value before
upload(req, res, (err) => {})
it is showing properly with out image info.
if I receive the value after upload(req, res, (err) => {})
No value is showing.
Full post request code:
app.post('/product/create', (req, res) => {
let filename;
upload(req, res, (err) => {
if(err){
res.render('index', {
msg: err
});
} else {
if(req.file == undefined){
res.render('index', {
msg: 'Error: No File Selected!'
});
} else {
res.render('index', {
msg: 'File Uploaded!',
filename = req.file.filename;
});
}
}
});
const product = {
title : req.body.title,
desc : req.body.desc,
image : filename,
}
});
configuring Multer:
const storage = multer.diskStorage({
destination: './public/uploads/',
filename: function(req, file, cb){
cb(null,file.fieldname + '-' + Date.now() + path.extname(file.originalname));
}
});
const upload = multer({
storage: storage,
limits:{fileSize: 1000000},
fileFilter: function(req, file, cb){
checkFileType(file, cb);
}
}).single('myImage');
function checkFileType(file, cb){
const filetypes = /jpeg|jpg|png|gif/;
const extname = filetypes.test(path.extname(file.originalname).toLowerCase());
const mimetype = filetypes.test(file.mimetype);
if(mimetype && extname){
return cb(null,true);
} else {
cb('Error: Images Only!');
}
}
Multer does not support 'req.file.filename' outside upload function. As filename, originalname, fieldname etc is inbuild API of multer. It is limited to upload function only.
Now, if you are trying to upload product values inside database then you have to create an insert function inside multer upload function only.
I am having a problem to redirect the page after a successful file upload using multer. With the file upload i am also saving some text into the database. Here's my code.
Question :
When the file and the contents are saved in the DB how can I redirect the page to a new URL ?
I am currently using res.redirect('product/item'); but nothing happens. I also tried using res.render, but the page did not redirect.
Multer method to upload a file to Amazon S3
var upload = multer({
storage: multerS3({
s3: s3,
bucket: 'nameofthebucket',
metadata: function (req, file, cb) {
var ext = file.originalname.split('.').pop();
cb(null, {fieldName: 'file.fieldname' + '.' + ext});
},
filename: function(req,file,cb){
var ext = file.originalname.split('.').pop();
cb(null, Date.now() + '.' + ext);
},
key: function (req, file, cb) {
var ext = file.originalname.split('.').pop();
cb(null, Date.now() + '.' + ext);
}
})
})
var upload = upload.array('fileup', 10);
The code responsible to upload the file and the content
router.post('/uploadfileandcontent',function(req,res,next){
upload(req,res,function(err) {
if(err) {
} else {
saveRecordsToDB(req, function(err,data){
if (err) {
res.redirect('/errorpage');
} else {
res. redirect('product/item');
}
});
}
});
});
Function that saves records to DB and makes the callback
function saveRecordsToDB (req, callback){
var args = {
data: {
"name" : req.body.name, //
"age" : req.body.age
},
headers: { "Content-Type": "application/json" }
};
// registering remote methods
client.registerMethod("postMethod", "http://url/uploadfileandcontent", "POST");
var req =client.methods.postMethod(args, function (data, response) {
callback(null, 'success?');
});
req.on('error', function (err) {
console.log('error');
});
}
Note: I also made use of NODE REST CLIENT to send http request.
This should work. Tell me if it doesn't.
router.post('/uploadfileandcontent', function(req,res,next){
upload(req,res,function(err) {
if(err) {
res.send('Error while uploading.');
}
saveRecordsToDB(req, function(err,data){
if (err) {
console.log(err);
req.flash('error', { msg: 'Error while saving data.' }); // Flash message -> need to configure your template to show it
}
// Saved to DB
req.flash('success', { msg: 'Saved' });
res.redirect('/product/item'); // go to this page
});
});
});
UPDATE
You will need to include const flash = require('express-flash'); to use flash message. Then you can load it to your app like this: app.use(flash());. The app is express loaded like this: const app = express();.
In your HTML you will access it in an array. Example using Jade:
//success
if messages.success
for success in messages.success
div #{success.msg} // Saved
//Error
if messages.errors
for error in messages.errors
div #{error.msg} // Error while saving data.
I have a form that asks for a text and a file. I use multer for the file upload. The problem is I cannot retrieve the text with req.body if i use enctype=multipart/form-data
Route file
router.post('/new-job', function(req,res,next){
upload(req,res,function(err) {
if(err) {
return res.end("Error uploading file.");
}
});
var newJob = {
job_name: req.body.job_name, //Cannot retrieve this two
job_desc: req.body.job_desc,
};
var newJobData = new Jobs(newJob);
newJobData.save(function(err,user){
if(err)
console.log(err);
});
res.render('jobs/new-job', {job_added:true});
});
Multer configs
var multer = require('multer');
var storage = multer.diskStorage({
destination: function (req, file, callback) {
callback(null, 'public/uploads');
},
filename: function (req, file, callback) {
callback(null, file.originalname);
}
});
Notes
I used method post
If i log the req.body.job_name it returns an undefined
If i remove the enctype=multipart/form-data i can retrieve the text just fine, though i cannot upload the file
You cannot access req.body contents until you're parsed the request, so either move your code inside your upload() callback, or get rid of the explicit upload() call entirely and just put upload before your route handler:
router.post('/new-job', upload, function(req, res, next) {
var newJob = {
// ...