React upload multiple photos via POST request - node.js

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

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

External API called in a route, and testing the route in node JS

I have the below route created in my application which calls another API for data:
newsr.get('/news', async (req, res) => {
var category = req.params.category;
try {
var url = 'http://newsapi.org/v2/top-headlines?country=in&category=general' + '&apiKey=36f3e29b704f41339af8439dc1228334';
const news_get = await axios.get(url)
res.status(200).json().render('category', { articles: news_get.data.articles })
// return res.status(200).json(news_get)
} catch (error) {
if (error.response) {
console.log(error)
}
}
})
The problem is, when I call the get API http://localhost:8080/news. I do not get the response from the external API. Can you please suggest what to do?

Get FormData from request in API

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

Issue getting correct POST data to save to mongodb from axios even though the console.log shows valid data

I am having issues getting data to save to my mongoDB through a post. I am able to get it to show correctly in a console.log but i'm not getting the data to the DB successfully.
The axios code:
async created() {
axios
.get("https://api.coinmarketcap.com/v1/ticker/?limit=2000")
.then((res, err) => {
if (res.status === 200) {
this.$store.state.CMC = res.data[0].coins;
// console.log(this.$store.state.CMC);
// Send a POST request
axios({
method: "post",
url: "http://localhost:5000/data",
data: { coins: this.$store.state.CMC }
}).catch(err, function() {
console.log(err);
});
} else {
console.log("Error: " + err);
}
});
}
The express code for the POST:
app.post("/data", (req, res) => {
console.log(req.body);
var Coins = new coins(req.body);
Coins.save(req.body, function() {
console.log("data was saved");
});
});
Like i said, i can see the data being shown in the clog when i go to post it, it's just not saving correctly.

How to add item with image with react-redux-saga with nodejs/multer

I am trying to save an item that has images in the form. I was able to save the items using postman, but getting issue when trying from react-redux-saga. I am using ant design for the form.
Front-end code:
handleSubmit = e => {
e.preventDefault();
this.props.form.validateFields((err, values) => {
if (!err) {
const { fileList } = this.state;
const formData = new FormData();
fileList.forEach(file => {
formData.append("files[]", file);
});
const postItemData = { ...values, images: formData };
this.props.createItem(postItemData);
}
});
};
saga:
When I try to console, I can get the item details with the image field as a formdata
{
let itemData = yield select(makeSelectPostItemData());
const token = yield select(makeSelectToken());
console.log(itemData, "itemData");
const response = yield call(request, `/item`, {
method: "POST",
headers: {
Authorization: `${token}`
},
body: JSON.stringify(itemData)
});
const successMessage = "Item saved successfully!";
yield put(postItemSuccess(response, successMessage));
}
nodejs:
const upload = multer({
storage: storage,
limits: { fileSize: 1000000 },
fileFilter: function(req, file, cb) {
checkFileType(file, cb);
}
}).array("images");
upload(req, res, err => {
if (err) {
console.log(err, "error");
res.send({ msg: err });
} else {
console.log(req, "req");
if (req.files === undefined) {
res.send({ msg: "Error: No file selected!" });
} else {
const { errors, isValid } = validatePostItem(req.body);
// check validation
if (!isValid) {
return res.status(400).json(errors);
}
const files = req.files;
}
}
});
On the last line const files = req.files. When I try from postman, I get file details, but when I try to request it from react, I have no req.files. How can I get the req.files from the react as I am getting from postman?
I have found the solution for this. In the handleSubmit, I have following code:
fileList.forEach(file => {
formData.append("files[]", file);
});
const postItemData = { ...values, images: formData };
this.props.createItem(postItemData);
Instead of spreading values and inserting the formData in images, what I did was put the all of them into formData.
fileList.forEach(file => {
formData.append("files[]", images);
});
formData.append("name", values.name);
formData.append("price", values.price);
formData.append("detail", values.detail);
this.props.createItem(formData);
With this, I could get req.files and req.body.name, req.body.price, req.body.detail in the node side. Quite different from the postman, but this worked for me.

Resources