Send image to server through js fetch - javascript

I am changing my form submission to make it more fluid via using fetch.
In order to process the value of my input image:
<input name="perfil" type='file' id="imageUpload />
And then, in order to upload it to Amazon S3,
I do this in my views.py:
if request.method == "POST"
image = request.FILES['perfil']
im = Image.open(image)
output = BytesIO()
rgb_im = im.convert('RGB')
rgb_im.save(output, format='JPEG', quality=90)
output.seek(0)
s3.Bucket('bucketname').upload_fileobj(output, request.user.email + '.profileImage')
But now (because i'm trying to implement fetch), I am getting the image file like this:
fetch(`url`, {
method: 'POST',
body: JSON.stringify({
image: document.querySelector('#imageUpload').files[0],
}),
headers: {
"Content-type": "application/json; charset=UTF-8",
"X-CSRFToken": getCookie('csrftoken')
}
})
}
The problem is that when I do request.body['image`] in the server (views.py), all I'm getting is this: "image":{}
And I don't know how to process this file in JS before I send it to the server (that will end up uploading it to amazon s3)

With this Example you can upload Images on a Server!
// Select your input type file and store it in a variable
const input = document.getElementById('fileinput');
// This will upload the file after having read it
const upload = (file) => {
fetch('http://www.example.net', { // Your POST endpoint
method: 'POST',
headers: {
// Content-Type may need to be completely **omitted**
// or you may need something
"Content-Type": "You will perhaps need to define a content-type here"
},
body: file // This is your file object
}).then(
response => response.json() // if the response is a JSON object
).then(
success => console.log(success) // Handle the success response object
).catch(
error => console.log(error) // Handle the error response object
);
};
// Event handler executed when a file is selected
const onSelectFile = () => upload(input.files[0]);
// Add a listener on your input
// It will be triggered when a file will be selected
input.addEventListener('change', onSelectFile, false);

Related

how to send mp3 blob as a post request?

I have an audio recorder and i need to send it as a post request in a third party server so it must be mp3.
My blob logs :
size:17981
type: "audio/webm;codecs=opus"
and my code :
async function sendBlob() {
const formData = new FormData();
formData.append("audio-file", getBlob);
const res = await fetch("/api/whisper", {
method: "POST",
// headers: {
// "Content-Type": `multipart/form-data`,
// },
body: formData,
});
const { result } = await res.json();
}
I already tried to create a File() and almost everything, i need to send it as a mp3 file.
I tried to send the blob, to append it in a FormDat() and in a File(), i tried to send the url but the post request only accepts mp3 files (if i upload the file and send it works, but i want to record and send direct)

Uploading Image to AWS presigned post URL using axios

I am trying to upload an image to an S3 bucket using a presigned URL generated using boto3 on Python. I have been using the example python code that was provided in the documentation and was successful (the image got correctly uploaded with the correct Content-Type). However, when trying to do this in Javascript for the purposes of our frontend application, I am really struggling to get it to work.
Here's the example dictionary returned by the backend:
{
"fields": {
"AWSAccessKeyId": "AKIAYS3VM3EBIFL7FKE5",
"key": "posts/623255a762fd9bdfbd13f91a",
"policy": "<very long string>",
"signature": "Qvc/sGBHk0uzirzIfR1YmE2kFlo="
},
"url": "https://hotspot-storage.s3.amazonaws.com/"
}
Here is the functioning Python code:
response = <json response object>
object_name = 'playground/example_profile_group.png'
response['fields']['Content-Type'] = "image/png"
# Demonstrate how another Python program can use the presigned URL to upload a file
with open(object_name, 'rb') as f:
files = {'file': (object_name, f)}
http_response = requests.post(response['url'], data=response['fields'], files=files)
# If successful, returns HTTP status code 204
print(http_response)
print(http_response.text)
Here is the non-functioning Javascript code:
const data = response.data;
let payload = data.fields;
payload['Content-Type'] = 'image/jpeg';
const file = {
uri: previewPath,
name: previewPath,
type: 'image/jpeg',
};
payload.file = file;
const url = data.url;
console.log(payload, "MY PAYLOAD")
axios({
method: 'post',
headers: {'Content-Type': 'multipart/form-data'},
url: url,
data: payload,
})
.then(function (response) {
console.log(response.data, 'uploaded');
const data = response.data;
})
.catch(function (error) {
console.log(
'error uploading image',
error.response.data,
);
});
})
.catch(function (error) {
console.log(
'error getting media link',
error.response.data,
);
});
This is the error that keeps getting returned:
error uploading image <?xml version="1.0" encoding="UTF-8"?>
<Error><Code>MalformedPOSTRequest</Code><Message>The body of your POST request is not well-formed multipart/form-data.</Message><RequestId>Q0ES6P4QP75YVVED</RequestId><HostId>eowLxSJQD1xP1EfHPnzGSJzXVGpPjurIMhkdwAD22JMvi9zRoFGg6Bq+mnUt/Lu7DNPY80iBDMc=</HostId></Error>
I have been stuck on this for an absurd amount of time, and cannot tell what I am doing wrong. Any help would be very much appreciated.
In order to send a multipart/form-data request body, you'll need to use a FormData instance instead of a JavaScript object.
For example
const { url, fields } = response.data;
const payload = new FormData();
payload.append("file", file); // this is the file blob, eg from <input type="file">
payload.append("Content-Type", "image/jpeg");
// add all the other fields
Object.entries(fields).forEach(([ key, val ]) => {
payload.append(key, val);
});
// No need to manually set content-type header, your browser knows what to do
const { data: result } = await axios.post(url, payload);
console.log("uploaded", result);

Axios: onUploadProgress event gets only triggered after video is uploaded completely

I am trying to track the progress of video upload and accordingly display it to the user.
This is the axios request that uploads the video.
const config = {
onUploadProgress: function (progressEvent) {
var percentCompleted = Math.round(
(progressEvent.loaded * 100) / progressEvent.total
);
console.group("profileActions.uploadProfileVideoURL");
console.log("progressEvent.loaded: ", progressEvent.loaded);
console.log("progressEvent.total: ", progressEvent.total);
console.log("percentCompleted: ", percentCompleted);
console.groupEnd();
},
};
axios
.post("/api/profile/uploadProfileVideoURL", videoData, config)
The problem is that it only gets triggered when video is completely uploaded.
I have found this discussed in this Github Axios Issue:
Only 100% can be fired in case your upload files are too small, or
download/upload speed is too fast. Try to upload 10mb file maybe.
So I tried uploading a 100Mb video, and the event still gets triggered at then end of the upload.
Any idea why is this happening?
And can I fine-tune axios for the event to get triggered at certain progress values?
Your code needs added the FormData and some headers, like (MIME type of the file) for request. You can use this logic:
First - create a utility function for handling upload with progress like below:
import axios from "axios";
const Upload = (files, customHeader, cbProgress, cb) => {
const config = {
onUploadProgress: function (progressEvent) {
var percentCompleted = Math.round(
(progressEvent.loaded * 100) / progressEvent.total
);
cbProgress(percentCompleted);
console.log(percentCompleted);
},
headers: {
...customHeader,
// "Content-Type": files[0].type,
// "Content-Type": "multipart/form-data",
},
};
let data = new FormData();
data.append(<field_name>, files[0]); // Name of the field for uploading
console.log({ ...customHeader });
axios
.post(<url>, data, config)
.then((res) => cb(res))
.catch((err) => console.log(err));
};
export default Upload;
Short description of the above code:
customHeader: pass any headers to the config, For example: "Content-Type", "Authorization", etc...
cbProgress: This is a callback, When the function is invoked and in progress.
cb: This is a callback, When the function is invoked and upload is completed.
Note: FormData, Used to send the file and you must use it.
The FormData interface provides a way to easily construct a set of
key/value pairs representing form fields and their values, which can
then be easily sent using the XMLHttpRequest.send() method. It uses
the same format a form would use if the encoding type were set to
"multipart/form-data".
Finally - You can call this utility function anywhere you want like below:
const customHeader = {
"Content-Type": files[0] && files[0].type, // This is an example
"Content-Type": "multipart/form-data", // This is an example
};
Upload(
files,
customHeader,
(percent) => {
// ...
},
(res) => {
// ...
}
);

I keep getting a Bad request error when trying to post Image to Cloudinary

i'm trying to upload an image to cloudinary using axios and react. I have two functions. One for appending the formData, and the other for making a request
// APPEND CLOUDINARY DETAILS
export function appendCloudinaryDetails(fileUrl){
let formData = new FormData();
formData.append("api_key", 'APIKEYHERE');
formData.append("api_secret", 'APISECRETHERE');
formData.append("file", 'fileUrl');
formData.append("cloud_name", fileUrl);
formData.append("upload_preset", "rhi2i6xg");
return formData;
}
// STORE THE DATA ON CLOUDINARY
export function storeOnCloudinary(formData){
return () => {
return axios.post("https://api.cloudinary.com/v1_1/my-company/image/upload", formData,{
headers: { "X-Requested-With": "XMLHttpRequest", "Allow-Control-Allow-Origin": "*" },
});
}
}
And this is how i use it:
// Append Cloudinary Details
let formData = appendCloudinaryDetails(this.state.backdropCroppedImageUrl);
// Store the backdrop on Cloudinary
this.props.storeOnCloudinary(formData).then(
response => {
...
}
);
But running this gives me a 400 error response. As shown below:
I don't know if this is a faithful copy of your code, or it was changed in order to hide sensitive information in the posted question, but according to it, you are appending to the formData the backdropCroppedImageUrl as the 'cloud_name' instead of setting it on 'file', and in 'file' you're setting a string.

Redux Form: How to add an image url to Redux Form before submitting it?

I have set up a form with file upload, where I upload an image to Cloudinary with separate request. What I want to do is to pick up an image url from the response Object from Cloudinary, pass it to my redux form and submit it all together with other form values to my server and database. So far my request looks like this
onChange(event) {
let formData = new FormData();
formData.append('file', event.target.files[0]);
formData.append('upload_preset', UPLOAD_PRESET);
axios({
url: `${COUDINARY_ROOT_URL}`,
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
data: formData
}).then((res) => {
console.log(res);
}).catch((err) => {
console.err(err);
});
My problem is, in what way can I add this image url data from response and pass it to my redux form before submitting it to my server?
If it is not an efficient way, would be really thankful for recommendations as well.
I believe redux form can only store state if you pass the data through a form component (e.g input tag, checkbox etc). But in this case you want to store the data to the store from a variable. I'm not aware of any means through redux form, so I recommend that you use redux instead.
Also, if you are saving the image url for the sole purpose of making another request to send both url and form data to your server and database, it is actually not necessary to save it in the redux store. You can just return it so that you can use it in the next promise chain, as shown in my code below.
But, if you still insist on saving it to the store perhaps for some other reason, what I would do is dispatch an action that saves the url in my redux store.
getImageUrl(formData) {
return axios({
url: `${COUDINARY_ROOT_URL}`,
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
data: formData
});
}
sendDataToServer(url, formData) {
// ... send url and formData to my server
}
onChange(event) {
let formData = new FormData();
formData.append('file', event.target.files[0]);
formData.append('upload_preset', UPLOAD_PRESET);
getImageUrl(formData)
.then(res => {
// assuming res.url contains the url and
// saveUrl is a method wrapped in dispatch from
// mapDispatchToProps
this.props.saveUrl(res.url);
// return res.url so that it can be used in the
// next then chain
return res.url;
})
.then(url => {
// we can get the url from previous promise chain
sendDataToServer(url, formData);
// ... rest of code
})
.catch(err => console.err(err))
}

Categories

Resources