Get FormData from request in API - node.js

I want to create an API which takes the form data as input and pass it to another API, but I am not able fetch that formdata from the request. please help me with this.
Here is the code of my API
router.post('/file', async (req, res) => {
const { file } = req.body;
try {
const url = `${API_URL}/api/file/upload`;
const response = await axios.get(url, file);
res.json({ status: true, data: response.data });
} catch (err) {
res.status(404).json({ status: false, error: 'Error in uploading' });
}
});
Here is the screenshot of data I want to sent by the postman

The key is how the variable in body is named.
If you are trying to make file upload i would recommend express-fileupload
You can get the file buffer from that.
Then you can use form-data to upload it somewhere else.
router.use(require(`express-fileupload`)());
router.post('/upload', async (req, res) => {
var FormData = require('form-data');
const buffer = req.files.foo.data // data is the file buffer // foo is the key/file name
var form = new FormData();
form.append('file', buffer);
form.submit('example.org/upload', function(err, res) {
res.send("done");
//Do something here
});
});

Related

I can't figure out how to upload multiple images from frontend to database

I have an API and I'm uploading images using multer. I built backend that works perfectly fine and my images are uploaded and stored in my folder when I use postman, but when I try to upload images using frontend i dont know how to send them. I'm trying to have formData and append my files and then put that in my req.body. I need to have fields with name 'photos' but when i put my data and log req.body on backend i get data: [object FormData] and photos as an empty array. Also when i log req.files i get an empty array. My photos after extracting values from them look like this [File, File]
const handleHotelSubmit = async (e) => {
e.preventDefault();
const data = new FormData();
Object.values(photos).map((photo) => data.append("photos", photo));
setIsLoading(true);
try {
await axios.post(
`/hotels`,
{ ...info, data, featured, rooms },
{
headers: {
"Content-Type": "multipart/form-data",
},
}
);
} catch (err) {
setError(err.message);
}
setIsLoading(false);
};
My multer
const multerStorage = multer.memoryStorage();
const multerFilter = (req, file, cb) => {
if (file.mimetype.startsWith("image")) {
cb(null, true);
} else {
cb(new AppError("Not an image. Please upload only images", 400), false);
}
};
exports.resizeImage = catchAsync(async (req, res, next) => {
console.log(req.files);
if (!req.files) return next();
req.body.photos = [];
await Promise.all(
req.files.map(async (file) => {
const filename = `hotel-${uuidv4()}-${Date.now()}.jpeg`;
await sharp(file.buffer)
.resize(500, 500)
.toFormat("jpeg")
.jpeg({ quality: 90 })
.toFile(`public/img/hotels/${filename}`);
req.body.photos.push(filename);
})
);
next();
});
const upload = multer({
storage: multerStorage,
fileFilter: multerFilter,
});
exports.uploadHotelPhotos = upload.array("photos", 5);
Again code works with postman so clearly the problem is in the frontend
Since you specified in the headers that the request body will be multipart/form-data, then you need to put all other fields (info, featured, rooms) inside the formData data variable

Express send response and catch it in client

im trying to have the user send some data to the server, where it gets saved into a db, after this I would like to send a message back to the user (for example containing the id of the newly added object), but I was not yet able to succeed my code:
router.post('/sendSnippet', function (req, res) {
req.on('data', function(data) {
User.findOne({email: req.user.email}).then((userToEdit) =>{
if(userToEdit){
var newSnippet = {
"types":[],
"code": data.toString()
}
userToEdit.snippets.push(newSnippet)
userToEdit.save().then(()=>{
res.redirect('/profile/');
----send response here----
})
}
})
})
});
and this is the client side function that sends the new data, im also guessing there is a better way to do this, but this worked so far (however any feedback would be appreciated!)
function sendSnippet(){
var xmlHttp = new XMLHttpRequest();
xmlHttp.open('POST', '/profile/sendSnippet', true);
xmlHttp.send(data to send);
}
thanks for any help in advance!
You can do it like this using async/await:
router.post('/sendSnippet', async (req, res) => {
const userToEdit = await User.findOne({email: req.user.email});
if (userToEdit) {
var newSnippet = {
"types":[],
"code": data.toString()
}
userToEdit.snippets.push(newSnippet);
const results = await userToEdit.save();
res.send({results: results._id});// it will send response
});
At the client side you can do this:
function sendSnippet(){
var xmlHttp = new XMLHttpRequest();
xmlHttp.onreadystatechange = function() {
if (xmlHttp.readyState === 4) {
console.log(xmlHttp.response);
}
}
xmlHttp.open('POST', '/profile/sendSnippet', true);
xmlHttp.send(data to send);
}
Check here for more details.

A super simple Multer question, nested file uploading

I'm trying to do an image upload with Multer and Express. Doing just an image upload is going fine and everything works, the problem is, I want to send more than just one photo. Let me explain. I got the most basic form ever, not worth sharing. Then when submitting the form with JUST an image, the axios request looks like this:
async onSubmit() {
const formData = new FormData();
formData.append('file', this.person.personData.file)
this.obj.file = formData
try {
await axios.post('/projects/new', this.obj.file);
this.message = 'Uploaded';
} catch (err) {
console.log(err);
this.message = 'Something went wrong'
}
},
The post route in Express to receive the image looks like this:
personRoutes.post('/new', upload.single('file'), (req, res) => {
console.log('BODY: ', req.body)
console.log('REQ.FILE: ', req.file)
const person = new Person({
personData: {
file: req.file.path
}
});
person.save()
.then(result => {
console.log('YES', result)
res.redirect('/projects')
})
.catch(err => {
console.log('KUT', err)
})
});
req.file is the upload.single('file') file. Req.body will hold the text fields, if there were any. Ez Pz, so far so good. Now, where things get a bit sketchy is, what if I wanted to upload more than just one photo? So my obj object would not only hold a file property but a few others aswell. Currently I am directly sending the formData file with
await axios.post('/projects/new', this.obj.file);
But if my obj contained more than just a file, I would have to to this:
await axios.post('/projects/new', this.obj);
But what in the world should my Express post route look like? Because req.file will now (as far as I know) forever be undefined because file is not defined inside req object. It is defined in req.body object. Accessing the file as req.obj.file won't do anything. Any help would be very much appreciated. I don't even know if it is possible. And if not, what other options do I have?
Thanks in advance!
upload.array('file') should work. any number of files will be received.
here is an example:
multer code:
const storage = multer.diskStorage({
destination: (req, file, cb) => {
cb(null, 'uploads')
},
filename: (req, file, cb) => {
cb(null, "image"+Date.now()+file.originalname);
}
});
const fileFilter = (req,file,cb)=>{
if(file.mimetype==="image/jpeg" || file.mimetype==="image/png"){
cb(null, true);
}else{
cb(new Error("File type is not acceptable"),false);
}
}
const uploadImages = multer({storage:storage,
limits:{
fileSize: 1024*1024*10
},
fileFilter:fileFilter}).array("shopImage");
app.post code:
app.post("/shop", function(req,res){
uploadImages(req,res,function(err){
if(err){
console.log(err);
res.status(400).json({message:err.message});
}else{
console.log(req.files);
console.log(req.body);
....
}
});
....
})

React upload multiple photos via POST request

I am trying to post to my backend multiple photos with their name that I get from a form.
If I have to upload just one photo it works perfectly, but it does not get the name nor upload all the photos, just the first one.
this is my code so far:
async function handleUpload() {
console.log("Upload pressed!");
console.log(photos);
let formData = new FormData();
formData.append("image", photos.files);
if (photos.length >= 1) {
try {
await fetch("/api/uploadPhoto", {
method: "POST",
data: formData
});
setPhotos([]);
} catch (err) {
console.log(err);
}
}
}
If I console.log the photos array I get this object:
I have tried mapping the format data for each element in photos trying to take the property name and saving both photos to my backend (Node + Mongoose), but I did not have success.
What would be a better approach in this situation?
Just for precision I attach also my route from the backend:
router.post("/uploadPhoto", async (req, res) => {
try {
let image = new UploadPhoto({ img: req.body });
image.img.contentType = "image/png";
image.save();
res.sendStatus(200);
} catch (err) {
res.json({ message: err });
}
});

writing file from post request in ExpressJS

Working with express to create a file transfer tool, and I've almost gotten everything completed. Just need to figure out how to get the data from the request written to file.
My issue appears to be stemming from not knowing where the file contents are placed in the request object.
My code to process sending the request
let file = watcher.getOneFile(config.thisLocation);
console.dir(file);
let contents = fs.readFileSync(file.fullPath, 'utf-8');
console.log(contents);
let form = {
attachments: [
contents
]
}
rq.post({
url: `http://${homeAddress}:${port}/files/?loc=${config.thisLocation}&file=${file.fileName}`,
headers: {'content-type':'application/x-www-form-urlencoded'},
formData: form
}, (err, res, body) => {
// body = JSON.parse(body);
console.log(body);
});
and when I get the request on the server, I'm not sure where the file contents actually are.
Code for handling the request
app.post('/files', (req, res) => {
console.log(req.query.loc);
// console.dir(req);
let incoming = watcher.getOutputPath(req.query.loc, config.locations);
console.log(incoming);
console.dir(req.body);
// console.log(req.body);
// let body = JSON.parse(req.body);
console.log(req.query);
let filename = path.join(incoming, req.query.file);
console.log(filename);
fs.writeFile(filename, req.body, (err) => {
if(err){
console.error(err);
}
console.log(`Successfully wrote file: ${path.join(incoming, req.query.file)}`);
});
res.sendStatus(200);
});
Where on the Request Object is the file contents?
Unfortunately you can't access the file content in any straightforward way. I recommend you to use busboy or similar package to parse form-data requests.
Here is how can you read file content using busboy and write it to the file system:
const Busboy = require('busboy');
app.post('/files', (req, res) => {
const busboy = new Busboy({ headers: req.headers });
busboy.on('file', (fieldname, file, filename, encoding, mime) => {
const newFilename = `${Date.now()}_${filename}`,
newFile = fs.createWriteStream(newFilename);
file.pipe(newFile);
file.on('end', () => {
console.log(`Finished reading ${filename}`);
});
});
busboy.on('finish', () => {
console.log('Finished parsing form');
res.sendStatus(200);
});
req.pipe(busboy);
});

Resources