React Native fetch, unexpected token - android

I'm trying to call a simple REST service with fetch api in React Native. I'm running the app on Android.
When I call await response.json() I get
Unexpected token � in JSON at position 0
, I tried also with await response.text(), and I get this text as result:
��Mn�0��B�[C�bn�u��?#�+�bLR�ҌBR.�
�����H�ծ�͛�#?>�g���t�%{���Z��؄u�>fs0]����H��'&��u�Z}��y�Z��2����i�d�G�>����R����6LL{j�j�7\���������d���L.���gٲXv�Lf��g�%T�~�\z�U8E܀���ڭ�c��#[G�;�T�������{�*�9�)��a½
���0�组V:ϒ���/�K��3�ݝ����W: c�^UV#�B�7�#�v
�+WG��#YL�|Ġ>q�=#�J}�3=��Q�]Հup^E�0 ^d'Ա
�^���b�.��2,��g2��R<���_rpV:!��<��^>�����{�e�#7m���nA�;n�������l�o�u��kW���r���
This is the code I'm using:
export function fetchMenu() {
return async(dispatch) => {
try {
dispatch(menuRequest(true));
console.log(Institucion.aplent);
var response = await fetch('http://<page_url>/api/moviles/personalizacion', {
compress: true,
headers: {
'aplentId' : Institucion.aplent,
'Accept-Encoding' : 'gzip,deflate'
}
});
console.log(response);
if(!response.ok) throw Error(response.statusText);
var data = await response.json();
console.log('Data:', data);
dispatch(menuSuccess(data));
}
catch(ex) {
console.log(ex);
dispatch(menuFailure(ex));
}
};
}
Note: I've changed the url to for security reasons, but I have the correct url in code.
I've tried with and without the Accept-Encoding header, the same result.
EDIT
If I disable deflate compression inside my REST API (on the server) it works ok, doesn't fetch support deflate compression?

Add these headers to the fetch call to ensure you receive JSON:
'Content-Type': 'application/json',
'Accept': 'application/json',

I would suggest seeing if it works without explicitly setting compression.
If you don't set the Accept-encoding header, react native should automatically zip and unzip it. So probably let it handle it. Instead try changing it to Accept header
export function fetchMenu() {
return async(dispatch) => {
try {
dispatch(menuRequest(true));
console.log(Institucion.aplent);
var response = await fetch('http://<page_url>/api/moviles/personalizacion', {
headers: {
'aplentId' : Institucion.aplent,
'Accept' : 'application/json'
}
});
console.log(response);
if(!response.ok) throw Error(response.statusText);
var data = await response.json();
console.log('Data:', data);
dispatch(menuSuccess(data));
}
catch(ex) {
console.log(ex);
dispatch(menuFailure(ex));
}
};
}

It was a server side issue, I changed the compression algorithm of the api, and it works well

Related

Fetch DELETE method on Android (React Native)

I make several requests from a React Native app to an API. Every request works fine both on iOS and Android except the DELETE method that does not work on Android. The call is correctly made, it goes through the API and the objects are deleted. But instead of getting the response, the call falls under the catch statement with [TypeError: Network request failed]. This does not happen in iOS.
Some people with the same problem were missing 'Content-Type': 'application/json' on the request headers which is not my case.
This is happening both locally, in testing and production stages (using an ip instead of localhost will do nothing).
The request is also successfully performed in Postman.
What can it be?
React Native 0.63.5
export const deleteApi = async (api: string, body?: any) => {
const userResponse = await getUserCredentials();
const authState = await getAuthState();
let response = await fetch(api, {
method: 'DELETE',
headers: await getHeaders(userResponse, authState),
body: JSON.stringify(body)
});
if (response.status === UNAUTHENTICATED_CODE)
response = await interceptor(response, userResponse, {
api: api,
method: 'DELETE',
body: body
});
return response;
};
leaveClass = async (
uuid: string,
onSuccess: () => void,
onFailure: (error: string) => void,
) => {
this.setLoading(true);
try {
const api = LEAVE_CLASS_API_PREFIX + uuid + LEAVE_CLASS_API_SUFFIX;
const response = await deleteApi(api);
if (response.status === SUCCESS_STATUS_CODE) {
onSuccess();
}
else {
const jsonResponse = await response.json();
if (jsonResponse.detail) onFailure(jsonResponse.detail);
else onFailure(translations.SOMETHING_WENT_WRONG);
}
} catch (error) {
console.log('leaveClass error: ', error);
}
this.setLoading(false);
};
You can use a network plugin for Flipper (https://fbflipper.com/docs/setup/plugins/network/), copy your request from it as a curl, and try to perform it from your terminal or postman. If it has the same error, the problem is not in React Native.

How to pass parameters in url using google cloud functions

I am using http calls to call a cloud function.
I have a URL in the form
url: 'https://api.shipengine.com/v1/labels/rates/rateid,
Now I need to pass values dynamically in rated whenever the function call happens.
How to pass the value into that URL.
I am attaching my cloud function too.
exports.shipmentlabelwithreturnid = functions.https.onRequest((req, res) => {
var request = require("request");
var rateid = req.body.RateId;
console.log(rateid);
var options = { method: 'POST',
url: 'https://api.shipengine.com/v1/labels/rates/'+ rateid,
headers:
{ 'content-type': 'application/json',
accept: 'application/json'
}
};
request(options, function (error, response, body) {
if (error) throw new Error(error);
console.log(body);
});
});
You should use promises, in your Cloud Function, to handle asynchronous tasks. By default request does not return promises, so you need to use an interface wrapper for request, like request-promise which "returns a regular Promises/A+ compliant promise", as follows:
....
const rp = require('request-promise');
exports.shipmentlabelwithreturnid = functions.https.onRequest((req, res) => {
var rateid = req.body.RateId;
console.log(rateid);
var options = { method: 'POST',
uri: 'https://api.shipengine.com/v1/labels/rates/'+ rateid,
headers:
{ 'content-type': 'application/json',
accept: 'application/json'
}
};
rp(options)
.then(response => {
console.log('Get response: ' + response.statusCode);
res.send('Success');
})
.catch(err => {
// API call failed...
res.status(500).send('Error': err);
});
});
Also, it is important to note that you need to be on the "Flame" or "Blaze" pricing plan.
As a matter of fact, the free "Spark" plan "allows outbound network requests only to Google-owned services". See https://firebase.google.com/pricing/ (hover your mouse n the question mark situated after the "Cloud Functions" title)
Since https://api.shipengine.com is not a Google-owned service, you need to switch to the "Flame" or "Blaze" plan.
On the fact that you have to use promises to handle asynchronous tasks, I suggest that you watch these videos from the Firebase team: https://www.youtube.com/watch?v=7IkUgCLr5oA&t=28s and https://www.youtube.com/watch?v=652XeeKNHSk which explain this key concept.

How to setup fetch for React Native Android using gzip?

My React Native app had been working fine on both iOS and Android but recently it gives Network request failed error on Android when the response is long.
I found out if I set the request's header to 'Accept-Encoding': 'gzip',, I was able to log response, but it only contains header and such:
{
type:'default',
status:200,
ok:true,
statusText:undefined,
headers:{
map:{
date:'Mon, 27 Aug 2018 18:39:23 GMT',
'content-type':'application/json',
'content-length':'215',
'content-encoding':'gzip',
'cache-control':'no-cache'
}
},
url:'http://test.essaybot.com/essay/list',
_bodyInit:'',
_bodyText:''
}
This is how I setup the fetch request:
const URLENCODED_HEADER = {
'Accept': 'application/json',
'Content-Type': 'application/x-www-form-urlencoded',
'Accept-Encoding': 'gzip',
'Content-Encoding': 'identity'
}
async function getEssayList() {
try {
let response = await fetch(SERVER_URL+'/essay/list', {
headers: URLENCODED_HEADER,
credentials: 'include',
});
let responseJson = await response;
console.log("[getEssayList]=======>", responseJson)
} catch(error) {
console.error(error);
throw error;
}
}

axios post request working in React Native ios but not in android

I know there many answers regarding to this question but I can't seem to find one that works for me. I'm sending a post request to my server using axios but it does not work in android although it does in ios. I'm currently using server ip address (not localhost), and I'm also sending headers when request but it is still not going through the network request for android.
import axios from 'axios';
const SERVER_URL = 'http://serverip:3000';
export function signin({ username, password }) {
return function(dispatch) {
axios.post(`${SERVER_URL}/user/authenticate`, { username, password }, { headers: { 'Content-Type': 'application/json' } })
.then((response) => {
console.log('login response', response);
dispatch({
type: USER_AUTH,
});
AsyncStorage.setItem('token', response.data.token || '');
})
.catch((response) => console.log('user sign in err', response));
};
}
Has anyone had similar issue like myself and know how to make this work?
Thank you,
Set header to
headers: {
Accept: 'application/json',
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
},

Including csrf token in a post request from react-native app

I have a react native app that posts and gets data from a remote server. In post, i need to include csrf token to avoid token mismatch errors. This is the backend laravel method
//Android Login
public function androidLogin(){
return response()->json([
'name' => 'Android Login',
'route' => 'androidLogin'
]);
}
This is the react native code(i have stripped out error catching code).
async handleSubmit(){
var me = this.state.message;
console.log('this connected',me);
let response = await fetch('http://not-brusselus.be/androidLogin', {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
'X-CSRF-TOKEN':'csrf_field()'
},
body: JSON.stringify({
session:{
email: 'chesterfield#gmail.com',
password: '123456',
}
})
});
//let res = await response.text();
if (true) {
console.log(response);
} else {
//Handle error
//let error = res;
//throw error;
}
}
The response shows laravel's token mismatch page. How can i send the csrf token successfully?.
Hang the CSRF token off of the window as defined in your main laravel layout file:
window.Laravel = {
csrfToken: '{{csrf_token()}}'
}
Then just use that in your javascript requests:
...window.Laravel.csrfToken
Edit
To the downvoter: This is literally how Laravel does it out of the box and recommends you do it as well.

Categories

Resources