Vanilla javascript Fetch API formData upload - javascript

I am trying to send form data to my API hosted on heroku.
On the API I had captured for empty input fields errors. It seems that I am sending data correctly (in my opinion). But I keep on receiving this error message which I know is a response from the API as it is a custom error:
{
"message": {
"typeofincident": "Type field is required"
}
}
Below is my javascript code:
function postIncident(e) {
e.preventDefault();
let token = sessionStorage.getItem('token');
let formdata = new FormData();
formdata.append("typeofincident", 'typeofincident', document.getElementById('record_type').value);
formdata.append("description", document.getElementById('description').value);
formdata.append("location", document.getElementById('location').value);
formdata.append('file', document.getElementById("media").files[0]);
fetch('https://issaireporterv2.herokuapp.com/api/v2/incidents', {
method: 'POST',
body: formdata,
headers: {
'Authorization': 'Bearer ' + token,
'Content-Type': 'application/x-www-form-urlencoded',
'content-type': 'multipart/form-data'
}
})
.then(res => res.json())
.then(data => {
if (data.Message) {
alert(data.Message)
} else {
alert(data.Error)
}
})
}
The request payload is as follows:
------WebKitFormBoundaryPoo9tZT7joBLu8YB
Content-Disposition: form-data; name="typeofincident"
------WebKitFormBoundaryPoo9tZT7joBLu8YB
Content-Disposition: form-data; name="description"
theft
------WebKitFormBoundaryPoo9tZT7joBLu8YB
Content-Disposition: form-data; name="location"
Latitude: -1.2094403999999999 Longitude: 36.8949247
------WebKitFormBoundaryPoo9tZT7joBLu8YB
Content-Disposition: form-data; name="file"; filename="user view.png"
Content-Type: image/png
------WebKitFormBoundaryPoo9tZT7joBLu8YB--
Can anyone assist where I am wrong? Thanks!

You set the Content-Type twice.
Once you claimed it was application/x-www-form-urlencoded, which it isn't.
Then you claimed it was multipart/form-data, but you didn't specify the boundary (WebKitFormBoundaryPoo9tZT7joBLu8YB … not that you can know what boundary will be generated for you) so it couldn't be parsed.
Don't override the fetch APIs generated Content-Type.

Related

The current request is not a multipart request in angular 11

i am trying to upload image in angular.
I do this step:
In service i use this settings:
postFormDataToServerMultiPart(action: string, formData) {
var headerss = new HttpHeaders({
"Content-Type": "multipart/form-data"
});
return this.http
.post(HttpService.apiUrl + action, formData, { headers: headerss })
.pipe(map((response: any) => response));
}
headers contain : "Content-Type": "multipart/form-data"
In component.ts :
var formData = new FormData();
formData.append("file", this.imageForm.get("profile").value);
if (this.Image) {
this.httpService
.postFormDataToServerMultiPart(
"api/upload/driver_image?id=" + this.employeeId,
formData
)
.subscribe((resp) => {
console.log("edit", resp);
if (resp.status == "SUCCESS") {
var dialogRef = this.dialog.open(DisplayPopupComponent, {
data: {
title: "Driver Updated Successfully!",
},
............
I receive this error :
error: "Internal Server Error"
message: "Current request is not a multipart request"
path: "/api/upload/driver_image"
status: 500
timestamp: "2021-07-09T13:45:23.443+0000"
what i do wrong?
What in miss?
This is failing because you are manually setting the Content-Type header instead of letting the browser do this for you. If you send that request with your code as-is, go into the dev tools and check out the request headers. You'll see:
Content-Type: multipart/form-data
This is actually not complete, as you are missing the boundary. Simply removing the manual headers should fix this because the browser will properly set the Content-Type and add the boundaries.
postFormDataToServerMultiPart(action: string, formData) {
return this.http
.post(HttpService.apiUrl + action, formData)
.pipe(map((response: any) => response));
}
After sending this request, check the dev tools again for the request headers and you'll see something like:
Content-Type: multipart/form-data; boundary=----12345678901234567890
For more information see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Type#directives

Fetch Request Data is missing Data in iOS

For the past few weeks, I have been trying to send audio files to a server in flask using the fetch function. The code for the post request is as follows
sendDataToServer = async (data, timecode, location = "postFileWebm/") => {
// data is a blob
// timecode is current time in millisecons
// location is the function to run in the flask server
const formData = new FormData();
formData.append("file", data);
const length = data.length || data.size;
console.log( formData.get( "file" ) );
return fetch(`${SERVER_URL}/${location}`, {
headers: {
name: `${this.props.id}${timecode}`,
segment: count,
id: this.props.id,
label: this.state.label,
gameId: this.props.gameId,
"Content-Length": length,
extension: "wav",
"Content-Range": "bytes " + 0 + "-" + length + "/" + length,
"Content-Transfer-Encoding": "binary",
"Accept-Ranges": "bytes",
},
method: "POST",
body: formData,
},);
};
In most devices the following code is functional and the request data is similar to
------WebKitFormBoundarybLCq4cl3vSy70eG4
Content-Disposition: form-data; name="file"; filename="blob"
Content-Type: audio/wav
RIFF$#WAVEfmt »wdata#
------WebKitFormBoundarybLCq4cl3vSy70eG4--
but in iOS the same code is missing the data and is usually
------WebKitFormBoundarybLCq4cl3vSy70eG4
Content-Disposition: form-data; name="file"; filename="blob"
Content-Type: audio/wav
------WebKitFormBoundarybLCq4cl3vSy70eG4--
Wanted to ask then if someone knew how to make this code function in iOS

How to rewrite angular ng-file-upload Upload.upload with JS fetch?

I need to upload file to server using fetch() from react native app
I have the following code in Angular which uses ng-file-upload:
in this function file variable is attached FormData
function addDocumentToMessage(messageId, file) {
data.filepath = file;
data.name = file.name;
return Upload.upload({
url: BackendUrl + "/messages/" + messageId + "/attachments/",
file: file,
data: data
})
.then(responseHandler)
.catch(errorHandler);
}
I tried to do following using fetch() but it doesn't work correctly: file is added to server but attachment and other fields are not saved there. Here is the code I tried:
document = { formData, name }
export const addDocumentToMessage = (token, logId, document) => {
const file = document.formData
const data = { filepath: file, name: document.name }
fetch(`${API_URL}/messages/${logId}/attachments/`, {
method: 'POST',
headers: { 'Authorization': `token ${token}`, 'Content-Type': 'multipart/form-data', Accept: 'application/json' },
body: JSON.stringify({ file: file, data: data })
})
.then(response => console.log(response.data))
.catch(error => console.log(error.message))
}
It seems that two Content-Types were mixed here:
multipart/form-data for sending binary content of the file in file
application/json for sending the some JSON data in body
Since HTTP requests only support one body having one Content-Type encoding we have to unify all of that to be multipart/form-data. The following example is using variable formData to combine (binary) file data with arbitrary JSON data.
export const addDocumentToMessage = (token, logId, document) => {
// commented these lines since I wanted to be more specific
// concerning the origin and types of data
// ---
// const file = document.formData
// const data = { filepath: file, name: document.name }
const fileField = document.querySelector("input[type='file']");
let formData = new FormData();
formData.append('file', fileField.files[0]);
formData.append('name'. fileField.files[0].name);
formData.append('arbitrary', JSON.stringify({hello: 'world'}));
fetch(`${API_URL}/messages/${logId}/attachments/`, {
method: 'POST',
headers: {
'Authorization': `token ${token}`,
'Accept': 'application/json'
// 'Content-Type': 'multipart/form-data',
},
body: formData
})
.then(response => console.log(response.data))
.catch(error => console.log(error.message))
}
The payload of HTTP request body would then look like this:
------WebKitFormBoundarypRlCB48zYzqAdHb8
Content-Disposition: form-data; name="file"; filename="some-image-file.png"
Content-Type: image/png
... (binary data) ...
------WebKitFormBoundarypRlCB48zYzqAdHb8
Content-Disposition: form-data; name="name"
some-image-file.png
------WebKitFormBoundarypRlCB48zYzqAdHb8
Content-Disposition: form-data; name="arbitrary"
{"hello":"world"}
------WebKitFormBoundarypRlCB48zYzqAdHb8--
References:
https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch#Uploading_a_file
https://developer.mozilla.org/de/docs/Web/API/FormData/append#Syntax

How to Upload Images using React, fetch, and Django REST

I'm encountering a bit of a roadblock in my dev work. I'm trying to upload a photo that I'm sending using FormData in fetch. I'm guessing my problem is in my content header or my back-end handling. Eitherway, I can't seem to find a way around it. I hope you guys can help me
general.js - this is my handler for a request
export const postDataWithImage = (url, data) => {
return fetch(url, {
body: data, // must match 'Content-Type' header
credentials: 'same-origin', //pass cookies, for authentication
method: 'POST',
headers: {
'Accept': 'application/json, application/xml, text/plain, text/html, *.*',
'Content-Type': 'application/x-www-form-urlencoded; charset=utf-8'
},
})
.then(response => response.json()); // parses response to JSON
};
user-creation.js - my actual usage of the function above (sending multiple data)
heres an image of the data I'm sending
![1] https://imgur.com/leBlC7L
const data = {...this.state, ...form};
const formData = new FormData();
Object.entries(data).forEach(([key, value]) => formData.append(key, value));
postDataWithImage('/users', data)
.then(data => {
if (data.error) {
console.log("theres an error");
this.setState({
error: data["error"]
});
console.log(this.state.error);
} else {
console.log(data["data"]);
}
})
.catch(error => message.warning(error.message));
views.py - my backend handler using Django REST not: this returns me an error either byte has no attribute 'get'... or an empty ModelDict for request.FILES
#staticmethod
def post(request):
print(request.body.get('image'))
print(request.FILES)
if "username" not in request.data or "password" not in request.data:
return Response(data={
"error": "Missing username or password"
}, status=400, content_type="application/json")
return Response(data=data, status=200, content_type="application/json")
Please help me I'm really stuck. Thank you!
I faced similar problem using Vue.js and Django.
Finally I noticed that the problem was that: boundary was not set to the header.
The solution is to remove headers from your request like this:
fetch(url, {
body: data, // assume this is some binary data
method: 'POST',
})
Then, your browser will automatically add proper headers for your request. And you will see boundary field which is added by your browser in your request headers.
Try to remove the "Content-Type" from the headers of fetch

javascript fetch is not posting to rest api endpoint while postman is doing

I have a rest api endpoint and I am checking it using POSTMAN which is posting correctly. But, when I am doing it using JAVASCRIPT FETCH, I am not able to post it. Below is my code for fetch:
const { inputAOI, wktForCreation } = this.state
fetch('http://192.168.1.127:8080/aoi/', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ userName: 'fuseim', aoiName: inputAOI, wkt: wktForCreation }),
mode: 'no-cors'
}).then(function (response) {
if (response.ok) {
return response.json()
} else {
throw new Error('Could not reach the API: ' + response.statusText)
}
}).then(function (data) {
console.log({ data })
}).catch(function (error) {
console.log({ error })
})
Below is the image for the request headers.
It is seen in the above image that in Request Headers, the Content-Type is still text/plain but I am sending application/json as shown in above fetch code.
Check the response preview in console.
Below is correct POSTMAN request:
As hinted in the comments, the problem is with the mode:"no-cors"
Content-Type is considered a simple header, and should be allowed without cors, but only with the following values:
application/x-www-form-urlencoded
multipart/form-data
text/plain
See: https://fetch.spec.whatwg.org/#simple-header
If you are running the API on the same host/port as the script, you should use mode: "same-origin" alternatively add the host/port that the script is running on as an allowed origin on the API.
For more information about CORS: https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS
Instead of
headers: {
'Content-Type': 'application/json'
}
you could try:
headers: new Headers({
'Content-Type': 'application/json'
})

Categories