Sending FormData not working in React-Native - javascript

I tried to communicate with an API to send a picture from an Iphone. I send form data by using Postman (key: mainPicture, value 'the file I choosed') and it's working well.
The problem come when I try to do it in js: the API don't find the file in my request.
Here is my code:
const formData = new FormData();
formData.append('mainPicture', {
uri: mainPicture.uri,
type: 'image/jpg',
name: `${mainPicture.id}.jpg`,
});
// ...
// api come from apisauce package
api.post(API_RES_IMG, formData, { headers: { ['Content-Type']: 'multipart/form-data' } })
Server say: "Error: Multipart: Boundary not found"
Without the content-type the server receive:
{"_parts":{"0":{"0":"mainPicture","1":{"uri":"assets-library://asset/asset.JPG?id=DE830A54-2526-44CB-81FE-00786D152080&ext=JPG","type":"image/jpg","name":"1e23519b-2006-4676-b63c-624e8198e17b.jpg"}}}}
Too much struggle from a simple thing.

Couple of issues I see here:
1) When using the fetch API, we don't need to set the Content-Type header, as fetch will take care of that, plus it will also take care of filling in the boundaries. I am assuming that this is the same with apisauce, however I might be wrong.
2) type: 'image/jpg' is not a valid mime type. It should be type: 'image/jpeg'.

you should add the content type
'Content-Type': type === 'form' ? 'multipart/form-data' : 'application/json',

Related

How to send a POST request as form-data when FormData is unavailable? (Airtable scripts)

The Cloudinary API requires to send data using multipart/form-data, but I'm working in an environment where FormData is not available.
How could I do something as simple as this, then?
const formData = new FormData();
formData.append('file', assetUrl);
formData.append('upload_preset', CLOUDINARY_UNSIGNED_UPLOAD_PRESET);
formData.append('cloud_name', CLOUDINARY_CLOUD_NAME);
console.debug(`Uploading file (id: ${id}) to Cloudinary`, CLOUDINARY_UPLOAD_URL, formData);
const response = await fetch(CLOUDINARY_UPLOAD_URL, {
method: 'POST',
body: formData,
});
I tried different approaches, but it seems the Cloudinary API is really sensitive about it, and doesn't allow sending data in any other format other than multipart/form-data.
Cloudinary API supports not only multipart/form-data, but also JSON and application/x-www-form-urlencoded.
If you're sending a string as the value of the file parameter, such as a remote URL (in your case) or Base64, then you can use any of the above-mentioned Content-Types.
For example, you could try the following example which will successfully upload the image into a cloud (you'll want to replace <your-cloud>, <file-url> and <upload-preset> with your actual values):
fetch('https://api.cloudinary.com/v1_1/<your-cloud>/image/upload', {
method: 'POST',
headers:{
'Content-Type': 'application/x-www-form-urlencoded'
},
body: new URLSearchParams({
'file': '<file-url>',
'upload_preset': '<upload-preset>'
})
});
Note that the cloud_name is derived from the URL you're sending the data to therefore it should not be sent in your request body.

Sending a csv from front-end to backend using axios

I am trying to send a csv file from my front end in reactjs to my back end in nodejs using axios. This csv file is selected via a browse UI button and stored in state using react. After searching online this is my code for the HTTPS request:
let formmData = new FormData();
formData.append('file', this.state.selectedFile);
const {data : QueryResult} = await axios({
method: 'post',
url: "https://localhost:...",
formData,
});
Note: this.state.selectedFile contains an object which when logged on console is:
File {name: "MyFile.csv", lastModified: 1614958303483, …}
I also would like to say that this endpoint works fine when using Postman as seen below:
After printing the request in my back-end in the case this request from my frontend I see:
body: {}
I don't understand what I am doing wrong and this passes nothing to my back-end.
I also saw that this was an open issue with axios on GitHub in the past.
Can this be achieved now with axios or should i use another module? Any ideas?
You need to do:
await axios({
method: 'post',
url: "https://localhost:...",
data: formData
});
because when you write just "formData", it becomes : { formData: formData } as per (new ES2015 object shorthand property name).
You can also use:
await axios.post('your_url', formData)

Converting Axios returned image into something vue can display in <img>

I ask for help from the community of stack overflow. Basically the long and short of the whole situation will be displayed below:
on a Vue page I am making a request to a Nodejs server using the code shown below
that node.js server is connecting to a Linux device and pulling an image off of it
that node.js server is then returning this image to the aforementioned Vue page
await axiosT({
method: 'post',
url: '{this is removed for security reasons}',
data: {this is removed for security reasons},
headers: {'Content-Type': 'application/x-www-form-urlencoded' },
responseType: 'text',
}).then(function (response) {
console.log(response.data);
}
this executes without error, and I have had this response work in postman with it successfully displaying the retrieved image. upon receiving the image and console logging it. I am met with the jumble of crap shown below which I can only assume is the image in one form or another; however, as right now all attempts I have made to display the image in any way has at worst, not worked with zero error messages, or at best simply caused the to display the missing image icon
������JFIF�����`�`�����<CREATOR: gd-jpeg v1.0 (using IJG JPEG v80), quality = 100
���C��������������������������������������������������������������������C������������������������������������������������������������������������������������������������������������������
���������������������}��������!1A��Qa�"q�2����#B���R��$3br�
�����%&'()*456789:CDEFGHIJST ... and so on and so on, etc etc you get the point
I am open to any suggestions, and if you need any further clarification on something, please don't be afraid to ask
thanks for all of the comments, you were all able to help me solve it
below is the working code, changing the response type to arraybuffer and adding the code found within the .then() successfully converted the image into base64 where it could set a variable bound to my <img>'s src (as shown further below).
let image = null;
await axiosT({
method: 'post',
url: '{this is removed for security reasons}',
data: {this is removed for security reasons},
headers: {'Content-Type': 'application/x-www-form-urlencoded' },
responseType: 'arraybuffer',
}).then(function (response) {
try {
image = ('data:image/jpeg;base64,' + btoa(
new Uint8Array(response.data).reduce((data, byte) => data +
String.fromCharCode(byte), '')
));
} catch (err) {
console.log(err)
}
})
this.foo_image = image
<img :src="foo_image">

Upload image through axios in React Native

I've been dealing with this problem for a while now apparently you can upload a image using FormData and appending the file but I am still unable to get this to work. I have already tried with the following threads:
React Native - Axios - Trying to upload image
form post with file attach throws network error / React Native + react native Image picker
How do I set multipart in axios with react?
My first problem revolves around FormData().append(), in most solutions a blob/file is configured using the uri property but I don't have access to this property (Is this related to Typescript?). So something like this:
formData.append("profile_photo", {
uri: values.imageURI
});
Here's the error TS is returning:
Argument of type '{ uri: string; }' is not assignable to parameter of type 'string | Blob'.
Object literal may only specify known properties, and 'uri' does not exist in type 'Blob'.ts(2345)
Another key points is setting up my axios client with the Content-Type header, I've done this during my POST request like so:
// Perform a profile post request
const profileResponse = await loginClient.post(
"/user_profile",
formData,
{
headers: {
"Content-Type": "multipart/form-data",
},
}
);
But by logging my request with Axios' interceptors, here how the request headers look like:
headers:
Accept: "application/json"
Authorization: "Bearer 36|8SVw1DntRKni0sUn4NDX9moLluCHyYcZSadfgI5B"
__proto__: Object
Just a few observations:
The image uri is changed using expo-image-picker.
I'm using Formik to build my form.
I'm using Typescript.
Solved by using the Form-Data module, then you can easily pass in the uri like so:
formData.append("profile_photo", {
uri: values.imageURI,
name: "image.png",
type: "image/png",
});
This could be improved by extracting the type from the uri tho.
You need to send these 3 values while uploading a file.
URI.
Name.
Type.
You can get all these values from the file picker.
Send it as
const formData = new FormData();
formData.append("profile_photo", {
uri: values.imageURI,
name: values.name || "profile_photo.png",
type: values.type || "image/png"
});
axios.post('upload_file', formData, {
headers: {
'Content-Type': 'multipart/form-data'
}
});

Change a jquery ajax POST request into a fetch api POST

I have some json data that I have been posting to an API using $.ajax but I would like to update this to use the fetch API. However I seem to have it setup the Fetch API request ends up returning a 403 so I must be missing something but I can't work it out.
Ajax request:
$.ajax({
type: 'POST',
url: url,
data: {
'title': data.title,
'body': data.body,
'csrfmiddlewaretoken': csrf_token,
'request_json': true
},
success: function (data) {
console.log(data)
}
});
Fetch attempt (one of many):
let payload = {
'title': data.title,
'body': data.body,
'csrfmiddlewaretoken': csrf_token,
'request_json': true
}
let request = new Request(url, {
method: 'post',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
body: JSON.stringify( payload )
});
fetch(request)
.then((response) => {
if (!response.ok) {
throw Error(response.statusText);
}
return response;
})
.then((response) => response.json())
I have tried with various different headers, content encoding and sending the data as form data using:
let form_data = new FormData();
form_data.append( "json", JSON.stringify( payload ) );
let request = new Request(url, {
method: 'post',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
body: form_data
});
...
Any help would be great and if you need any more info let me know
Thanks
To port an existing jQuery.ajax request to fetch, you need to consider that jQuery always includes cookies for you, but fetch does not.
Quoting MDN (emphasis mine):
Note that the fetch specification differs from jQuery.ajax() in mainly two ways that bear keeping in mind:
- The Promise returned from fetch() won’t reject on HTTP error status [ ... ]
- By default, fetch won't send or receive any cookies from the server, resulting in unauthenticated requests if the site relies on maintaining a user session (to send cookies, the credentials header must be sent).
Edit: spec has changed since then, so this should no longer be a problem:
Since Aug 25, 2017. The spec changed the default credentials policy to same-origin. Firefox changed since 61.0b13.
So the following (returning to original answer) only applies to "older" browsers.
Thanks David Richmond from comments :)
So you get 403 (Forbidden) because your API likely relies on cookies for authentication/authorization (even in your case, where you send a csrfmiddlewaretoken, the server-side framework might still expect a cookie with that -- guessing Django?).
To fix this, add credentials: "same-origin" to your Request (*), like so:
let request = new Request(url, {
method: 'post',
credentials: 'same-origin',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(payload)
});
(*) Valid options for credentials are:
omit: Never send cookies. This is the default (and your problem).
same-origin: Only send cookies if the URL is on the same origin as the calling script.
include: Always send cookies, even for cross-origin calls.
You say:
'Content-Type': 'application/x-www-form-urlencoded'
and
body: JSON.stringify( payload )
JSON Encoding is not the same thing as WWW Form Encoding!
You also tried
form_data.append( "json", JSON.stringify( payload ) );
FormData objects are converted to Multipart MIME.
Multipart MIME is also not the same as WWW Form Encoded data.
JSON nested inside Multipart MIME even less so.
This question describes how to convert an object (payload) into a Form Encoded string.

Categories