Formdata not being sent through to NodeJS backend - javascript

I have a function that should send FormData as an axios.post call to my api. It gets activated with a press of a button
const sendCard = (card) => {
debugger;
let data = new FormData();
data.append("itemID", itemID);
data.append("comment", comment);
data.append("dateStart", dates[0]);
data.append("dateEnd", dates[1]);
data.append("qtyWant", qtyWant);
requestBooking(data);
};
and here is the axios part:
export const requestBooking = async (data) => {
return await api
.post(`/booking/request`, data)
.then((data) => {
return "DONE!";
})
.catch((err) => {
console.log(err.response.data);
});
};
the api is an import from a config.js file, and everything there works with all the other aspects of my website.
I have another FormData object being posted into the api, and that one works properly, even though there is no differences at all...
Here is the accepting function on the back end
app.post(
"/api/booking/request",
request
);
exports.request = (req, res) => {
res.status(200).send("Reached");
};
where req.body is just an empty object ({})
This all seems like it should work. And I don't know what am I missing

Related

Why files are not being uploaded in the back-end from react-front-end

Recently I started working on a project where I am using react as my front-end and node as my back-end. In this project, I have a requirement to upload multiple images from the front-end and my back-end will receive the files and they will be uploaded in cloudinary. I have created an API route for that. Which works just fine! but when I am trying to do that same thing from my react front-end, I am not receiving any files just getting an empty [] but when I was using postman, I was receiving all the files properly inside an array. What is the issue here? I guess this is a problem from my front-end. But I can't figure out what is the problem.
I am sharing my front-end and back-end code:-
front-end
const Upload = () => {
const [fileAra, setFileAra] = useState([]);
// for sending these files to the back-end
async function uploadProduct() {
try {
const formData = new FormData();
formData.append("assets", fileAra);
const res = await fetch("/get_product/post_product", {
method: "POST",
body: formData,
});
const body = await res.json();
if (res.status === 200) {
history.push(`/profile/${user._id}`);
toast.dark(body.message);
}
} catch (err) {
console.log(err);
}
}
return (
<input type="file" multiple onChange={(e) => setFileAra(e.target.files)} />
<button onClick={uploadProduct}></button>
)
}
Back-end route
router.post(
"/post_product",
checkAuth,
multer.array("assets", 10),
async function(req, res, next) {
try {
const pictureFiles = req.files;
// map through images and create a promise array using cloudinary upload function
const multiplePicturePromise = pictureFiles.map((picture) =>
cloudinary.uploader.upload(picture.path, {
folder: `devR-Commerce/products/${req.user.name}`,
})
);
const imageResponses = await Promise.all(multiplePicturePromise);
// separating each of the images into objects
const allImagesSeparatedInObject = imageResponses.map((img) => ({
photoId: img.public_id,
photoUrl: img.secure_url,
}));
// creating a new product instance
const newProduct = new Product({
user: req.user._id,
images: allImagesSeparatedInObject,
});
// saving the product in my database
const savedProduct = await newProduct.save();
// creating relation between these two collections: Product and User
await User.updateOne(
{ _id: req.user._id },
{ $push: { products: savedProduct._id } }
);
res
.status(200)
.json({ message: "Product uploaded successfully", newProduct });
} catch (err) {
next(err);
}
},
);
Note: The back-end route works properly I have tested with Postman. But when I try to send the same files from my front-end, I don't receive any files. Might be a problem in the front-end. Please help me if you know the answer. If you need any additional information about this problem, please feel free to ask. Thanks for checking this out
You need to append each file to the FormData one by one and not attach the whole array at once, like this.
async function uploadProduct() {
try {
const formData = new FormData();
for (let i = 0; i < fileAra.length; i++) {
formData.append(fileAra[i].name, fileAra[i])
}
const res = await fetch("/get_product/post_product", {
method: "POST",
body: formData,
});
const body = await res.json();
if (res.status === 200) {
history.push(`/profile/${user._id}`);
toast.dark(body.message);
}
} catch (err) {
console.log(err);
}
}
you can check out this article explaining FormData for further details

how to send zip file as body in a post request in react?

Let's say I have a zip file uploaded by user, how do I pass it to the server for process?
I have front end function to handle zip file. I can verify that fileUploaded holds the zip file.
const onImport = async evt => {
const fileUploaded = evt.target.files[0];
const response = await extractImport('/extractimport', fileUploaded);
};
Helper function used above
export const extractImport = async (url, fileUploaded) => {
return await fetch(url, {
method: 'POST',
headers: {'accept': 'application/zip'},
body: fileUploaded
});
};
router for post call.
And here, req body is empty. I don't know what went wrong here.
router.post('/extractimport',
asyncWrapper(async (req, res) => {
//req.body is empty here, I dont understand why.
try {
const result = await extractImportPost(req.body);
res.status(200).json(result).end();
} catch (err) {
res.status(500).json({errors: [{error: err.message}]}).end();
}
})
);
extractImportPost utility used above is as below
const extractImportPost= async (zipFile) => {
// zipFile is undefined here.
// how do I pass the zip file to this place for process
}
Thank you for your time.

Sending a HTTP POST REQUEST with image and text

How can I send an image along with a text in VueJs to my backend ExpressJs?
Right now, what I did was create two http post request
NOTE this.albumName and this.albumDesc are just text and the formData is an image.
createAlbum() {
const formData = new FormData();
for (let file of Array.from(this.myAlbumImages)) {
formData.append("files", file);
}
if (this.albumName) {
axios
.post("http://localhost:9001/image/album", {
ALBUM: this.albumName,
DESCRIPTION: this.albumDesc
})
.then(resp => console.log(resp))
.catch(err => console.log(err));
setTimeout(function() {
axios
.post("http://localhost:9001/image/album", formData)
.then(resp => console.log(resp))
.catch(err => console.log(err));
}, 3000);
this.albumName = "";
this.albumDesc = "";
} else {
alert("Please fill the above form.");
}
},
and here is my Backend.
This creates the folder based on the passed data and it also creates a named undefined folder
router.post('/album', (req, res) => {
let sql = "INSERT INTO GALLERY SET ALBUM = ?, DESCRIPTION = ?";
let body = [req.body.ALBUM, req.body.DESCRIPTION]
myDB.query(sql, body, (error, results) => {
if (error) {
console.log(error);
} else {
let directory = `C:/Users/user/Desktop/project/adminbackend/public/${req.body.ALBUM}`;
fse.mkdirp(directory, err => {
if (err) {
console.log(err);
} else {
console.log(directory);
}
})
}
})
I think this is because of NodeJS is Asynchronous that's why it creates the undefined folder.
Reason for behavior you see is you are sending two different requests to the same route. 1st includes ALBUM and DESCRIPTION form field values, but not the files. Second (inside setTimeout) will contain just files and no other fields, so referencing them like req.body.ALBUM will return undefined
You can send all data (text fields and files) in one request. Just do this:
const formData = new FormData();
for (let file of Array.from(this.myAlbumImages)) {
formData.append("files", file);
}
formData.append("ALBUM", this.albumName);
formData.append("DESCRIPTION", this.albumDesc);
axios.post("http://localhost:9001/image/album", formData)
.then(resp => console.log(resp))
.catch(err => console.log(err));
FormData always uses content type multipart/form-data. To parse it on server side you need Express middleware that parses multipart forms, and gives you access to both fields and image/s. For example multer...
for the first part the client may can help you this link How to post image with fetch?
const fileInput = document.querySelector('#your-file-input') ;
const formData = new FormData();
formData.append('file', fileInput.files[0]);
const options = {
method: 'POST',
body: formData,
// If you add this, upload won't work
// headers: {
// 'Content-Type': 'multipart/form-data',
// }
};
fetch('your-upload-url', options);
and for the seerver part cant help you this link
Node Express sending image files as API response
app.get('/report/:chart_id/:user_id', function (req, res) {
res.sendFile(filepath);
});
and oficial documentation about this
http://expressjs.com/en/api.html#res.sendFile

JavaScript express, node and CSVtoJSON

I'm currently developing a 'Dupe Finder' web app for a co-worker. This is my first time using the 'csvtojson' package.
I'm reading from the file just fine on the server, but when I send a response back to the client (ideally containing a json object) I'm getting this very odd console log and I'm not sure if its correct:
To get this response, I have a button on the home page, when clicked, the client makes an http request on the home directory of the server, called '/getnums'. The request reads from the CSV then should be returning and obj with its contents. It is sort of doing that, in the screenshot, if I click the tick next to promiseValue, it'll give me an array. But i'm not sure why its returning a Promise..anyway..
api.js:
var CSVDATA = () => {
fetch('/getnums')
.then(res => {
console.log(res.json())
})
}
export default {
CSVDATA,
}
'/getnums' goes to my router, which is simly router.get('/', mainController.getNums)
in the controller is where the reading begins:
const csv = require('csvtojson')
module.exports = {
getNums: (req, res, next) => {
const csvFilePath = `${__dirname}/../../client/readFrom/main.csv`
csv().fromFile(csvFilePath)
.then(jsonObj => {
return res.status(200).json(jsonObj)
})
.catch(e => {
req.error = e
next()
})
},
}
anyone have an idea what might be going on here?
That is simply how .json() works.
It returns promise so you need to handle it asynchronously
var CSVDATA = () => {
fetch('/getnums')
.then(res => res.json())
.then(json => console.log(json));
}
export default {
CSVDATA,
}
MDN link

Check Axios request url before sending

API requests are failing because the URL generated by Axios is incorrect due to my config. I know what the request url is suppose to look like, so I want to see the request url Axios generates.
I can point Axios to my local server and see the requests there, but I want to debug this on the client. I want to play with the config, and see how the requests change. Is there a way to output the request url from Axios before or after sending?
// param format
{ address: 'Vancouver', key: GOOGLE_API_KEY }
// Geocode sample
https://maps.googleapis.com/maps/api/geocode/json?address=1600+Amphitheatre+Parkway,+Mountain+View,+CA&key=YOUR_API_KEY
_request = async (...args) => {
const { outputFormat, params } = args
const instance = axios.create({
baseURL: `https://maps.googleapis.com`,
})
const response = await instance.get('/maps/api/geocode/${outputFormat}?', {
params,
})
// I want to see the url generated by Axios so I can debug the issue
console.log(response)
}
I am within the Expo, React Native environment.
Working example using fetch:
const url = `https://maps.googleapis.com/maps/api/geocode/json?address=vancouver&key=${GOOGLE_API_KEY}`
fetch(url)
.then((response) => response.json())
.then((data) => {
console.log(data)
})
.catch(function(error) {
console.log(error)
})
Solution used:
_request = async (obj) => {
const { outputFormat, params } = obj
const instance = axios.create({
baseURL: `https://maps.googleapis.com`,
})
instance.interceptors.request.use(function (config) {
console.log(config)
return config
}, function (error) {
return Promise.reject(error)
})
const response = await instance.get(`/maps/api/geocode/${outputFormat}`, {
params,
})
}
You can turn on debug mode and look at the network tab as mentioned in the other answer, or you can intercept axios and console.log or do whatever you want with the request before it's sent:
axios.interceptors.request.use(function (config) {
// Do something before request is sent
console.log(config)
return config;
}, function (error) {
// Do something with request error
return Promise.reject(error);
});
You can just use axios#getUri([config]) (source) to perform the same logic as the request. It merges the configurations (e.g. the given config and the instance configuration), merges the url with the baseURL, and appends any params using the paramSerializer.

Categories

Resources