unable to post with file upload using axios react js - reactjs

I am trying to post multi-part form data with file upload using React and Axios. I tried the same in Postman and this is working correctly. But in react, I get "Required request part 'file' is not present". My code:
const selectedFile = event.target.file.files[0].name;
const formData = new FormData();
formData.append('name',this.state.name);
formData.append('description',this.state.description);
formData.append('file', selectedFile);
// Here I am passing content type and token and Post request .
axios({
method: 'post',
url: 'http://localhost:8080/user/1/savecategory',
data: formData,
headers: {
'Authorization':`Bearer ${passToken}`,
'Content-Type':'multipart/form-data'
}
})
.then(
(response) => {
alert("Category Saved..!");
},
(error) => {
console.log(error);
alert("Failed..!");
}
);

You haven't add the file field to the FormData Object. you only passed the name of the file as the second parameter.
de definition of append method is like this
For regular form field
formData.append(name, value);
And for Field field you can add It using this syntax
formData.append(name, value, filename);
Here selectedFile contain the name of the file which is selected in the file input field
const selectedFile = event.target.file.files[0].name;
When you call formData.append('file', selectedFile); you are passing the name of the file as value of the form element with name file and not the file It self.
to pass the file It self you should perform It like this
const selectedFile = event.target.file.files[0];
After that you can call formData.append('file', selectedFile);
Learn more about FormData.append

Related

Sending image file and data in one post request

I'm trying to send image file and data in one post request with axios:
const fd = new FormData();
fd.append("image", selectedFile, selectedFile.name);
let data = {
category: category,
title: title,
post: text,
image: fd
};
//console.log(fd);
const headers = {
"Content-Type": "multipart/form-data"
};
const url = "http://localhost:5000/blog/posts";
axios
.post(url, fd, headers)
.then(resp => { ...
Flask back-end:
image = request.files['image']
category = request.files['category']
title = request.files['title']
post = request.files['post']
log output:
werkzeug.exceptions.BadRequestKeyError: 400 Bad Request: The browser (or proxy) sent a request that this server could not understand.
KeyError: 'category'
What am I doing wrong ?
You use a FormData object which is transmitted as "multipart/formdata". In other words, in multiple parts of data that are transmitted in individual sections of a broadcast.
Use the FormData object for all data that you want to transfer. Add the data as entries to the FormData object.
const fd = new FormData();
fd.append ("image", selectedFile, selectedFile.name);
fd.append("category", category);
// ...
The different types of data and files can be reached within the route in a different way from the request object.
Use request.form in your route for all entries that do not represent a file.
image = request.files['image']
category = request.form['category']
# ...
Possibly use .get(key[, ...]) to bypass the KeyError and get None if the data is not available or to pass a default value.
category = request.form.get('category', 'Uncategorized')
You create a data object, but don't seem to do anything with it. If you're using FormData, you should append all your data points to it. So your code should look something like this:
const fd = new FormData();
fd.append("image", selectedFile, selectedFile.name);
fd.append("category", category);
fd.append("title", title);
...
Then you can just post it the way you post it:
axios
.post(url, fd, headers)
.then(resp => { ...

Spring API request giving "Content type 'application/octet-stream' not supported" error, however request is successful when using Postman

I am trying to send an API request through my React frontend to Spring backend. When I send the request I get this error:
Could not resolve parameter [0] in private org.springframework.http.ResponseEntity com.example.bottlecap.controllers.BottlecapController.entryForm(com.example.bottlecap.domian.Bottlecap,org.springframework.web.multipart.MultipartFile): Content type 'application/octet-stream' not supported
However, when I set up the request using Postman it goes through fine. I presume there may be an issue with how I am setting up my FormData on the React end. However, I have had little luck figuring it out.
My API is supposed to recieve an object that holds data about my submission as well as an image that goes with the submission. In my Postman request, I am creating a form data that holds a JSON file that holds all the object data and a random image just for testing. As I said, the requets goes through fine with this. However, in the frontend code, I am parsing through the object data as Json and adding it to a FormData as well as adding the image to the FormData.
Here is my Spring Controller:
#RequestMapping(path ="/bottlecap/entry", method = RequestMethod.POST, consumes = {MediaType.MULTIPART_FORM_DATA_VALUE, MediaType.APPLICATION_OCTET_STREAM_VALUE})
private ResponseEntity entryForm(#RequestPart("cap") Bottlecap cap, #RequestPart("file") MultipartFile image){
System.out.println(cap);
cap.toString();
System.out.println("Test");
return ResponseEntity.ok().build();
}
Here is my react Frontend form submission handler:
handleSubmit = event =>{
console.log(this.state.page);
console.log(this.state.page);
event.preventDefault();
const cap ={
"name":this.state.name,
"brand":this.state.brand,
"yearMade":parseInt(this.state.yearMade),
"country": this.state.country,
"description":this.state.description,
"yearFound":parseInt(this.state.yearFound),
"isAlcoholic":"true"
};
const stringCap = JSON.stringify({cap});
console.log(cap);
var formData = new FormData();
formData.append('cap', JSON.parse(stringCap));
formData.append('file',this.state.imageFile)
axios.post('http://localhost:8080/bottlecap/entry', formData, {headers:{'Content-Type':'multipart/form-data'}})
.then(res=>{
console.log(res);
console.log(res.data);
//window.location = "/success"
this.setState({pageDone:true})
this.setState({pageLoading:true})
})
}
Here is a screenshot of my Postman request if it may help.
Also here is the contents of the json file I am sending through on Postman, if it may help as well.
{"name":"post-test",
"brand":"post-test",
"yearMade":1000,
"country":"post-test",
"description":"post-test",
"yearFound":1000,
"isAlcoholic":"true"}
The last change I did was adding a header to the axios API request, but still no luck.
In postman, for parameter named cap, you're sending a .json file. But in your reactjs code, you're doing
formData.append('cap', JSON.parse(stringCap));
JSON.parse will create a javascript object which is not what your backend is expecting. You need to send it as a JSON file.
Not tested, but this might give you the idea.
const json = JSON.stringify(cap);
const blob = new Blob([json], {
type: 'application/json'
});
var formData = new FormData();
formData.append('cap', blob);
formData.append('file', this.state.imageFile)
axios.post('http://localhost:8080/bottlecap/entry', formData, {headers:{'Content-Type':'multipart/form-data'}})
.then(res=>{
console.log(res.data);
}
This is my fetch sample in Vue3, and it works thanks to you. Thanks!
let formData = new FormData();
formData.append('productJsonData', new Blob([JSON.stringify(productJsonObject)], {type: 'application/json'}));
formData.append('file', image); // This image comes from an <v-file-input> TAG
const response = await fetch(
`http://.../addProduct`,
{
headers: { 'Accept': 'application/json' },
method: 'POST',
body: formData
}
);
const responseData = await response.json();
if (!response.ok) {
console.log('REST error: [' + responseData.error + ']')
throw error;
}

Post File object within an array of object with Axios?

Are we able to upload File objs within an object with other keys? I've been asked to add an import_type key to an object, but its already a File obj when I'm upload it using a package called react-dropzone https://react-dropzone.js.org/
So I'd have to do something like
[{file: //File obj,
import_type: 1
}, {file: //File obj,
import_type: 1
},]
This is being sent in a post request
export const uploadFiles = (formData) => {
return axios.post("/upload", formData, {
headers: {
"Content-Type": "multipart/form-data",
},
});
};
I'm getting an error "Missing Data" and it is only showing this as the data sent...
data: ["file": {"path": "",} //file path
"import_type": 1 //value I want sent with the obj
Source of issue: I was passing in an entire array and axios was not looking for that but a single file.
My solution: I'm mapping through the array instead and using Promise.all for each array value so that it will be processed properly.

Multiple file uploads to Cloudinary with Axios in React

I have tried implementing the superagent way of uploading multiple files in axios. But somehow, I'm getting an error in console
Failed to load https://api.cloudinary.com/v1_1/xxxx/image/upload:
Request header field Authorization is not allowed by
Access-Control-Allow-Headers in preflight response.
My upload handler looks like this
uploadFile(){
const uploaders = this.state.filesToBeSent.map(file => {
const formData = new FormData();
formData.append("file", file);
formData.append("upload_preset", "xxxxx");
formData.append("api_key", "xxxxx");
formData.append("timestamp", (Date.now() / 1000) | 0);
return axios.post(url, formData, {
headers: { "X-Requested-With": "XMLHttpRequest" },
}).then(response => {
const data = response.data;
const fileURL = data.secure_url
console.log(data);
})
});
// Once all the files are uploaded
axios.all(uploaders).then(() => {
// ... perform after upload is successful operation
console.log("upload completed ", uploaders);
});
}
I have got this example from here
Another thing is confusing to me. In superagent we can attach parameters to the request field which includes API Secret Key of Cloudinary like this:
const paramsStr = 'timestamp='+timestamp+'&upload_preset='+uploadPreset+secretKey;
const signature = sha1(paramsStr);
const params = {
'api_key': 'xxxx',
'timestamp': timestamp,
'upload_preset': uploadPreset,
'signature': signature
}
Object.keys(params).forEach(key => {
uploadRequest.field(key, params[key])
});
But in that example, it is not mentioned how to append the secret key and other params to axios.
You will need to generate the signature on your backend, and then perform the upload with the generated signature.
You can generate a signature via the following instructions- https://support.cloudinary.com/hc/en-us/articles/203817991-How-to-generate-a-Cloudinary-signature-on-my-own-
You can also take a look at the following example on how to append the signature to your request. It's in PHP, however, the guidelines still apply.
https://gist.github.com/taragano/a000965b1514befbaa03a24e32efdfe5

React dropzone, how to upload image?

Using React dropzone, I've successfully accessed the image using the onDrop callback. However, I'm trying to upload to Amazon S3 by sending the image to my server, saving to an S3 bucket, and returning a signed url to the image back to the client.
I can't do this with the information I have so far and the docs don't seem to mention this to my knowledge.
onDrop triggers a function call in my redux actions with the files:
export function saveImageToS3 (files, user) {
file = files[0]
// file.name -> filename.png
// file -> the entire file object
// filepreview -> blob:http:localhost:3000/1ds3-sdfw2-23as2
return {
[CALL_API] : {
method:'post',
path: '/api/image',
successType: A.SAVE_IMAGE,
body: {
name: file.name,
file: file,
preview: file.preview,
username: user
}
}
}
}
However, when I get to my server, I'm not sure how to save this blob image (that's only referenced from the browser.)
server.post('/api/image', (req, res) => {
// req.body.preview --> blob:http://localhost:3000/1ds3-sdfw2-23as2
// req.body.file -> {preview:blob:http://localhost:3000/1ds3-sdfw2-23as2}, no other properties for some reason
})
React Dropzone returns an array of File objects which can be sent to a server with a multi-part request. Depend on the library you use it can be done differently.
Using Fetch API it looks as follows:
var formData = new FormData();
formData.append('file', files[0]);
fetch('http://server.com/api/upload', {
method: 'POST',
body: formData
})
Using Superagent you would do something like:
var req = request.post('/api/upload');
req.attach(file.name, files[0]);
req.end(callback);

Resources