Sending image file and data in one post request - reactjs

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 => { ...

Related

Passing files from react-dropzone to express server

I'm currently trying to send my files to my express server but every time I try and send my request the body is empty. After some research, it seems like they would not be stored in req.body so I'm not sure how to actually access the files that I've stored in my formdata.
Clientside code
export default async function UploadToFireStorage(accepetedfiles,fileVals){//Index are 1-1
const formData = new FormData();
formData.append('files', accepetedfiles);
try{
const response = await fetch(`https://someUrl`,{
method:"POST",
body: JSON.stringify(formData)
})
const jsonData = await response.json()
console.log(jsonData) //Attempt to see how my req is formed
}catch(error){
console.log(error)
}
}
express code
app.post('/uploadNewFiles',async(req,res)=>{
try{
const files = req.? // im not sure what to access after sending my formdata
for(let file = 0;file < files.length;file++){
let storageRef = ref(storage, `files/${files[file].path}`);
let uploadTask = await uploadBytesResumable(storageRef, files[file]);
}
res.json(files)
}catch(error){
res.json('Error: ' + error)
}
})
So just to clarify my question. I know when I make a fetch request I can package data that needs to be sent so I can post it and then extract it using something like let someVar = req.body.someVar and I've tried that with my file array but am unable to get my file array back and i'm not totally sure how to access it from req.
To properly post the files, don't use JSON.stringify. Set the body equal to formData directly. See this answer for more detail.
On the server side, you'll need to use a body parser that can handle multi-part form data, like multer . See this answer for more detail.

How to use Axios.post() in a post request containing a json object request-body and a multipart form data (MP4)

Hi I Was wondering how I can send a a single axios post request containing a json object as the request body and also multipart form data (Mp4 file).
In my example I want to send 'details' and 'file'. I have tried sending details and file as 2nd and 3rd arguments to the axios.post() method but from what I can tell axios.post only accepts 2 args.
I have also tried appending the details and then the file, to the form data, but this does not work either.
If I split these into 2 seperate post calls, it works fine, but my application requires these to happen together.
I am getting the following error in my spring console:
[org.springframework.web.HttpMediaTypeNotSupportedException: Content type 'multipart/form-data;boundary=----WebKitFormBoundaryqKyZ0R2SyFeDNCVp;charset=UTF-8' not supported]
Here is the error in my web dev tools console:
xhr.js:210 POST http://localhost:9191/api/123/file/upload 415
Id really appreciate any suggestions
const FileUpload = () => {
const [file, setFile]= useState(null)
const[details, setDetails] = useState({consent:false,
idConfirmed:false,
label:"",
roundId:""})
const changeHandler=(e)=>{
setFile(e.target.files[0]);
setDetails(prevDetails=>({
...prevDetails,
consent:true,
idConfirmed:true,
label:"test_Label"
}));
};
const handleSubmission=(e)=>{
e.preventDefault();
const data = new FormData();
data.append("file", file)
data.append("file", details)
console.log("Data: ", data)
axios.post(`${process.env.REACT_APP_URL_NEW_ROUND_VID}/123/file/upload`, data,
{
headers:{
"Content-Type":"multipart/form-data"
}
})
.then(res=>{
console.log("Data: ",res.data)
console.log("success")
})
.catch((e)=>{
console.log("Error", e)
})
//})
};
Here is my rest end point in Springboot:
#PostMapping(
path = "{patientId}/file/upload",
consumes = MediaType.MULTIPART_FORM_DATA_VALUE,
produces = MediaType.APPLICATION_JSON_VALUE)
public void addWardRound(#PathVariable("patientId") String patientId,
#RequestParam("file") MultipartFile file,
#RequestBody WardRequest wardRequest){
WardRoundService.isFileEmpty(file);
WardRound round = service.saveRound(wardRequest);
String roundId = round.getRoundId();
service.uploadVid(patientId, roundId, file);
}
you can stringify and send the JSON data. but by using this method you need to parse it in the server!. it could be difficult
The best method is splitting it into 2 APIs
you can merge both API requests in UI by merging both APIs using promise.All
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all
const promise1 = axios.get(URL1);
const promise2 = axios.post(URL2, data);
Promise.all([promise1, promise2]).then(function(values) {
console.log(values);
});
or else if you need to use the result of first API
then call the second API inside the response of first API itself

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

How to send image to server with Blob type using Axios in React Native?

I try to select a picture from the gallery, and I got data like below:
{
"exif":null,
"localIdentifier":"9F983DBA-EC35-42B8-8773-B597CF782EDD/L0/001",
"filename":"IMG_0003.JPG",
"width":500,
"modificationDate":null,
"mime":"image/jpeg",
"sourceURL":"file:///Users/vichit/Library/Developer/CoreSimulator/Devices/3BBFABAC-2171-49AA-8B2B-8C2764949258/data/Media/DCIM/100APPLE/IMG_0003.JPG",
"height":500,
"creationDate":"1344451932"
}
For this time, I want to send this picture to the server with Blob type using Axios.
I don't know how to convert this picture to a Blob type.
It's simple:
async function uploadToServer(sourceUrl) {
// first get our hands on the local file
const localFile = await fetch(sourceUrl);
// then create a blob out of it (only works with RN 0.54 and above)
const fileBlob = await localFile.blob();
// then send this blob to filestack
const serverRes = await fetch('https://www.yourAwesomeServer.com/api/send/file', { // Your POST endpoint
method: 'POST',
headers: {
'Content-Type': fileBlob && fileBlob.type,
},
body: fileBlob, // This is your file object
});
const serverJsonResponse = await serverRes.json();
// yay, let's print the result
console.log(`Server said: ${JSON.stringify(serverJsonResponse)}`);
}
And run like uploadToServer("file:///Users/vichit/Library/Developer/CoreSimulator/Devices/3BBFABAC-2171-49AA-8B2B-8C2764949258/data/Media/DCIM/100APPLE/IMG_0003.JPG")
It took me forever to figure it out, but it makes sense now.
I hope that helps someone!

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

Resources