React Native - Fetch POST not working - javascript

I am having huge troubles getting my fetch POST calls to work on iOS. My standard Fetch calls work and the Fetch POST calls work fine on android but not iOS.
The error that comes up is "Possible Unhandled Promise Rejection (id: 0): Unexpected token < in JSON at position 0"
It actually saves the post data to my server but throws that error.
I tried debugging the network request using GLOBAL.XMLHttpRequest = GLOBAL.originalXMLHttpRequest || GLOBAL.XMLHttpRequest; before the API call coupled with using CORS in my chrome debug tools. From there I can see that it is making two post calls one after the other. The first one has type "OPTIONS" while the second one has type "POST". It should probably be noted that the call works in the App while using CORS and the line of code above.
I'm very confused and have exhausted all avenues.
My code im using for refrence is as follows.
return fetch(url,{
method: 'post',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify(data)
}).then((res) => res.json());

If JSON.stringify is not working, then try to use FormData.
import FormData from 'FormData';
var formData = new FormData();
formData.append('key1', 'value');
formData.append('key2', 'value');
let postData = {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'multipart/form-data'
},
body: formData
}
fetch(api_url, postData)
.then((response) => response.json())
.then((responseJson) => { console.log('response:', responseJson); })
.catch((error) => { console.error(error); });

You use the following code for POST request in react native easily. You need to only
replace the parameter name and value and your URL only.
var details = {
'userName': 'test#gmail.com',
'password': 'Password!',
'grant_type': 'password'
};
var formBody = [];
for (var property in details) {
var encodedKey = encodeURIComponent(property);
var encodedValue = encodeURIComponent(details[property]);
formBody.push(encodedKey + "=" + encodedValue);
}
formBody = formBody.join("&");
fetch('http://identity.azurewebsites.net' + '/token', {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/x-www-form-urlencoded'
},
body: formBody
}).
.then((response) => response.json())
.then((responseData) => {
console.log("Response:",responseData);
}).catch((error) => {
Alert.alert('problem while adding data');
})
.done();

I would guess the response you are receiving is in HTML. Try:
console.warn(xhr.responseText)
Then look at the response.
Also, IOS requires HTTPS.
Edit: Possible duplicate: "SyntaxError: Unexpected token < in JSON at position 0" in React App

Here is an example with date that works for me!
The trick was the "=" equal and "&" sign and has to be in a string format in the body object.
Find a way to create that string and pass it to the body.
====================================
fetch('/auth/newdate/', {
method: 'POST',
mode: 'cors',
redirect: 'follow',
body: "start="+start.toLocaleString()+"&end="+end.toLocaleString()+"",
headers: new Headers({
"Content-Type": "application/x-www-form-urlencoded;charset=UTF-8"
})
}).then(function(response) {
/* handle response */
if(response.ok) {
response.json().then(function(json) {
let releasedate = json;
//sucess do something with places
console.log(releasedate);
});
} else {
console.log('Network failed with response ' + response.status + ': ' + response.statusText);
}
}).catch(function(resp){ console.log(resp) });

server node.js?
npm i cors --save
var cors = require('cors');
app.use(cors());
res.header("Access-Control-Allow-Origin: *");

Related

I am getting a response code of 400 or 429

I am working on REST API.
From my end, everything seems to be fine. I've tried multiple libraries (AXIOS, request, fetch) in order to make a PUT call.
However, I keep on getting 429 or 400 as a response code.
Below is the implemented code
const fetch = require('node-fetch');
const date= new Date();
const bodyData = `{"fields":
{
"priority":{"name":"Blocker"},
"date":"${date}"
}
}`;
await fetch('url', {
method: 'PUT',
headers: {
'Authorization': `Basic ${Buffer.from('username:password').toString('base64')}`,
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: bodyData
})
.then((response) => { console.log(response.data) }) //print the result
.catch((err) => {return res.json({'msg': "Something went wrong"})});
Observation:-
The 429 error should not appear if the structure of the fetch call is incorrect.
I am not sure If am missing something, could you guys help me please?

Can't upload image using Angular's HttpClient

I am able to upload an image perfectly fine using the native fetch POST:
let formData = new FormData();
formData.append('file', event.target.files[0]);
console.log(event.target.files[0]);
fetch('http://localhost:8080/file/upload', {
method: 'POST',
headers:{
'Authorization': 'Bearer ' + JWT
},
body:formData
}).then(response => console.log(response));
However, when I try this using Angular's HttpClient, the request fails since the 'Content-Type': 'multipart/form-data' is not added.
My Angular code:
The file where I'm calling the service:
this.fileSaverService.uploadImage(event.target.files[0]).subscribe(
(data)=>{
console.log(data);
},
(error) => {
console.log(error);
}
);
The fileSaverService:
uploadImage(fileToUpload) {
const endpoint = 'http://localhost:8080/file/upload';
const formData: FormData = new FormData();
formData.append('file', fileToUpload);
return this.api
.post(endpoint, formData, { headers: {'Content-Type': 'multipart/form-data'} });
}
The this.api:
post(endpoint: string, body: any, reqOpts: any = {}) {
reqOpts.headers = this.handleHeaders(reqOpts.headers);
return this.http.post(endpoint, JSON.stringify(body), reqOpts);
}
If I add the header manually when using HttpClient, I get this header without the boundary:
However the native fetch adds this header automatically with the boundary if I don't specify a header and this works perfectly:
What are my options here?
There are two problems with the code in your question:
By setting Content-Type to multipart/form-data yourself, the serialisation of your FormData will not result in the correct header with boundaries being set behind the scenes.
In your post function, you have JSON.stringify(body), which is converting your FormData object into a JSON string. After doing this, you're simply attempting to POST a string rather than a complete FormData object.

Cannot get images to upload to wp/v2/media with React Native

I've been all over here and https://github.com/WP-API/WP-API/ and https://wordpress.org/ and cannot find anyone talking about this. I can get it working using postman and selecting the file, however i cannot get it work submitting it as either "multipart/form" or "image/png".
I also cannot find anything detailing exactly how the request should look. I can create attachments but they're empty images of the correct size using base64 data as the post body. I feel like I'm missing something simple but cannot figure out what it is. I'm using postman to abstract out other distractions, my headers are:
POST /wp-json/wp/v2/media
Content-Type: image/png
Content-Disposition: attachment;filename=image_1.png
Cache-Control: no-cache
Authorization: Bearer {JWT_Auth_token}
body is just
{
data:image/png;base64,{base64_string_here}
}
I get a returned response like it created an attachment, but when I check in the wp admin it's an blank file, that appears to be the correct kb size but doesn't display. What am I missing???
Finally figured it out! With the help of this WP Trac issue https://core.trac.wordpress.org/ticket/41774.
So my request looks like this now:
async function uploadImageAsync(urlbase, uri, base64, token) {
let apiUrl = urlbase + '/wp-json/wp/v2/media';
let formData = new FormData();
//dynamically get file type
let uriParts = uri.split('.');
let fileType = uriParts[uriParts.length - 1];
//generate some random number for the filename
var randNumber1 = Math.floor(Math.random() * 100);
var randNumber2 = Math.floor(Math.random() * 100);
formData.append('file', {
base64,
name: `photo-${randNumber1}-${randNumber2}.${fileType}`,
type: `image/${fileType}`,
});
let options = {
method: 'POST',
body: formData,
headers: {
Accept: 'application/json',
'Authorization' : 'Bearer ' + token,
'Content-Type': 'multipart/form-data',
'Cache-Control' : 'no-cache',
},
};
console.log('header options: ',options);
console.log('form-data options: ',formData);
return fetch(apiUrl, options);
}
When base64 comes in it's formatted simply as base64: {base64-string}. Not data:image/type, since that is specified in the form data. The other thing that's key here is setting the key of form to 'file'.
The original answer did not work for me, so I changed "uri: base64,". now it's working fine
formData.append('file', {
uri: base64,
name: `photo-${randNumber1}-${randNumber2}.${fileType}`,
type: `image/${fileType}`,
});
I wanted to put my solution somewhere in case other people find it useful. I am using react-native and redux, this solution is an action within the redux framework.
export const uploadMedia = image => {
return async function(dispatch, getState) {
const { token } = getState();
const uriParts = image.uri.split('.');
const fileType = uriParts[uriParts.length - 1];
const bodyFormData = new FormData();
bodyFormData.append('file', {
base64: image.base64,
name: `photo-qa.${fileType}`,
type: `image/${fileType}`
});
try {
const request = await fetch(
'http://stagingsite.test/wp-json/wp/v2/media',
{
method: 'POST',
headers: {
Accept: 'application/json',
Authorization: `Bearer ${token}`,
'Content-Type': 'multipart/form-data; boundary=__boundrytext__'
},
body: bodyFormData
}
);
const response = await request.json();
console.log({
text: 'uploadMedia', response, request
});
} catch (error) {
return ErrorHandler(error);
}
};
};

res.json() is undefined when mocking post request with fetch-mock and isomrphic-fetch

I'm using fetch-mock to test my client action creators in cases where there is an async call being made to the BE.
While all get requests are working well I'm having hard time doing the same to post and put requests.
Attached here a code example that if works I believe that my actual code will work as well.
I'm using import fetchMock from 'fetch-mock' for mocking the response and require('isomorphic-fetch') directly to replace the default fetch
I added some comments but I do get a response with status 200 (if I change the mocked response status to 400 I get it as well. The problem is that res.json() resulted with undefined instead of the mocked result body.
Using JSON.stringify is something that I used after not being able to make it work without it.
const responseBody = {response: 'data from the server'};
fetchMock.once('http://test.url', {
status: 200,
body: JSON.stringify(responseBody),
statusText: 'OK',
headers: {'Content-Type': 'application/json'},
sendAsJson: false
}, {method: 'POST'});
fetch('http://test.url',
{
method: 'post',
body: JSON.stringify({data: 'Sent payload'}),
headers : {
'Accept': 'application/json',
'Content-Type': 'application/json',
}
})
.then(function (res) {
expect(res.status).toEqual(200); // Pass
res.json();
})
.then(function (json) {
console.log(json); // print undefine
expect(json).toEqual(responseBody); // Fail expected value to equal: {"response": "data from the server"} Received: undefined
done();
})
Mocking GET requests is working just fine
I also tried using it with fetchMock.post but had no luck
Would also appreciate if someone knows how I can test the post request sent payload as well (can't see any reference for that in the documentation)
In your first then, you don't have an explicit return, with the keyword return
If you don't do a return, the next then doesn't know the value. That's why your json is undefined.
For example:
var myInit = { method: 'GET', mode: 'cors', cache: 'default' };
fetch('https://randomuser.me/api/',myInit)
.then(function(res) {
return res.json()
})
.then(function(r) {
console.log(r)
})
So, for you:
const responseBody = {response: 'data from the server'};
fetchMock.once('http://test.url', {
status: 200,
body: JSON.stringify(responseBody),
statusText: 'OK',
headers: {'Content-Type': 'application/json'},
sendAsJson: false
}, {method: 'POST'});
fetch('http://test.url',
{
method: 'post',
body: JSON.stringify({data: 'Sent payload'}),
headers : {
'Accept': 'application/json',
'Content-Type': 'application/json',
}
})
.then(function (res) {
expect(res.status).toEqual(200); // Pass
return res.json(); // return here
})
.then(function (json) {
console.log(json); // print undefine
expect(json).toEqual(responseBody); // Fail expected value to equal: {"response": "data from the server"} Received: undefined
done();
})

Javascript fetch response cutoff

I'm starting to learn react-native and ran into some problems while using fetch on Android.
try {
let response = await fetch(REQUEST_URL, {
method: "POST",
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify({
***parameters***
})
});
let responseJson = await response;
if(responseJson){
// console.log(responseJson);
console.log(responseJson.text());
// console.log(responseJson.json());
}
} catch(error) {
console.error(error);
}
The request is sent correctly but the answer isn't shown in it's totality:
(**loads more data before**){"ID":"779","DESCRICAO":"ZXCVB","CLIENTENUMERO":"10133","CLIENTENOME":"Lda 1","TREGISTO":"2015\\/11\\/24 09:34:15","TTERMO":"","SITUACAO":"C","TIPO":"P","NOTIFICACOES":"email","NOTIFI_TAREFA":"","ESFORCOS_TOT":"4","TEMPOGASTO_TOT":"0:01:44","TEMPOGASTO_PES":"0:01:44","PROJECTO":"New Products","USERNAME":"AT","UREGISTO":"S","EMCURSO":"0","TULTIMO":"2015\\/12\\/18 20:37:56","EQUIPA":"","NIVEL":"AVISAX"},{"ID":"783","DESCRICAO":"123","CLIENTENUMERO":"10133","CLIENTENOME":"Lda 1","TREGISTO":"2015\\/11\\/24 09:43:26","TTERMO":"","SITUACAO":"C","TIPO":"P","NOTIFICAC
As you can see, the JSON object isn't complete. Sending the same request using other methods in a browser returns the JSON correctly.
I'm wondering if this is an actual issue with fetch or with Android.
I've tried setting size and timeout parameters to 0 in fetch but it did nothing.
Edit: also tried using synchronous fetch instead of async, with the same effect:
fetch(REQUEST_URL, {
method: "POST",
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify({
***params***
})
})
.then((response) => response.text())
.then((responseText) => {
console.log(responseText);
})
.catch((error) => {
console.warn(error);
}
Also tried:
console.log(responseJson);
and
console.log(responseJson.json());
Edit for further clarification:
When using response.json(), the response is shown as json (as to be expected) but it's still incomplete.
Edit :: Issue was with console.log limiting the number of characters it displays in the console.
Quick question:
Can you get the json object in its entirety if you hit the endpoint with postman? It could very well be your server/service that is cutting off the message.
Lastly, (and I see you mentioned this above) but I always use the 'json' method off the response obj when I know that is the notation type - which should return a promise.
fetch(REQUEST_URL, {
method: "POST",
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify({
***params***
})
})
//get the response and execute .json
.then((r) => r.json())
//then listen for the json promise
.then((j) => {
console.log(j);
})
.catch((error) => {
console.warn(error);
}
Let me know what happens and if you get the full response with postman (or fiddler compose).

Categories

Resources