i am trying to fecth html page with react-native-html-parser - react-native

How to parse html page from fetch response?
I have checked both async and regular promise syntax but nothing seems to compile:
const fetch = require('node-fetch'); var DOMParser = require('react-native-html-parser').DOMParser;
function getbooks() {
fetch('https://github.github.io/fetch/').then(function(response) {
if (response) {
return response
} else {
var error = new Error(response.statusText)
error.response = response
throw error
}
})
}
const books=getbooks();
console.log(books);
var DOMParser = require('react-native-html-parser').DOMParser;
var doc = new DOMParser().parseFromString(
books);
console.log(doc);
console.log('end');

What gets returned from your endpoint?
You Can try:
NOTE: Your trying to log a response from something that is asyncrhonus. You need to use
async and await (with promises). Something like...
async function getBooks(){
var response = await fetch('https://github.github.io/fetch/', {
method: 'GET',
headers: {
Accept: 'application/json',
},
}).then((response) => {console.log(response);return response})
.then((responseJson) => {
return responseJson.json();
})
.catch((error) => {
console.error(error);
return {error: "Couldn't get books"}
});
console.log(response);
}
getBooks();

Related

RN "TypeError: Network request failed" - production - random

I know some questions about the subject has been opened here and there, but my issue is different :
all the other ones appear in dev mode, in my case it's in production,
a very big percentage of requests pass, a few of them is TypeError: Network request failed - but sometimes for critical requests
it's random, not always the same request. Sometimes it passes, sometimes not.
it appears to three on my projects, one is on AWS the other one on Clever-Cloud, both are projects between 1000 and 5000 users, servers are quite too big for what they do - I think I removed the risk of a server fault. Even if... I can reproduce locally when I don't start the api locally. So it's like the api is not responding, but as I said, I don't think so.
I have no clue where to dig anymore...
I can give you my API.js service file, maybe you'll find what's wrong ?
import URI from 'urijs';
import { Platform } from 'react-native';
import NetInfo from '#react-native-community/netinfo';
import { getUserToken, wipeData } from '../utils/data';
import { SCHEME, MW_API_HOST } from '../config';
import deviceInfoModule from 'react-native-device-info';
import { capture } from '../utils/sentry';
const unauthorisedHandler = (navigation) => {
wipeData();
navigation.reset({ index: 0, routes: [{ name: 'Auth' }] });
};
const checkNetwork = async (test = false) => {
const isConnected = await NetInfo.fetch().then((state) => state.isConnected);
if (!isConnected || test) {
await new Promise((res) => setTimeout(res, 1500));
return false;
}
return true;
};
class ApiService {
host = MW_API_HOST;
scheme = SCHEME;
getUrl = (path, query) => {
return new URI().host(this.host).scheme(this.scheme).path(path).setSearch(query).toString();
};
execute = async ({ method = 'GET', path = '', query = {}, headers = {}, body = null }) => {
try {
const config = {
method,
headers: {
'Content-Type': 'application/json',
Accept: 'application/json',
appversion: deviceInfoModule.getBuildNumber(),
appdevice: Platform.OS,
currentroute: this.navigation?.getCurrentRoute?.()?.name,
...headers,
},
body: body ? JSON.stringify(body) : null,
};
const url = this.getUrl(path, query);
console.log('url: ', url);
const canFetch = await checkNetwork();
if (!canFetch) return;
let response;
// To try to avoid mysterious `TypeError: Network request failed` error
// that throws an error directly
// we try catch and try one more time.
try {
response = await fetch(url, config);
} catch (e) {
if (e?.toString().includes('Network request failed')) {
// try again
await new Promise((res) => setTimeout(res, 250));
console.log('try again because Network request failed');
response = await fetch(url, config);
} else {
throw e;
}
}
if (!response.ok) {
if (response.status === 401) {
const token = await getUserToken();
if (token) unauthorisedHandler(API.navigation);
return response;
}
}
if (response.json) return await response.json();
return response;
} catch (e) {
capture(e, { extra: { method, path, query, headers, body } });
return { ok: false, error: "Sorry, an error occured, technical team has been warned." };
}
};
executeWithToken = async ({ method = 'GET', path = '', query = {}, headers = {}, body = null }) => {
const token = await getUserToken();
if (token) headers.Authorization = token;
return this.execute({ method, path, query, headers, body });
};
get = async (args) => this.executeWithToken({ method: 'GET', ...args });
post = async (args) => this.executeWithToken({ method: 'POST', ...args });
put = async (args) => this.executeWithToken({ method: 'PUT', ...args });
delete = async (args) => this.executeWithToken({ method: 'DELETE', ...args });
}
const API = new ApiService();
export default API;
Talking with experts here and there, it seems that it's normal : internet network is not 100% reliable, so sometimes, request fail, for a reason that we can't anticipate (tunnel, whatever).
I ended up using fetch-retry and I still have a few of those, but much less !

filter query param not working through axios get from my vue js application?

whenever a user types anything into the textfield, an axios get request to the url
http://sandbox4.wootz.io:8080/api/data/1/action/?filter={id}like'%TE%' is made and it is supposed to return back all the filtered results based on the search(what user has typed) as a response. But currently rather than returning the filtered results as a response it is giving out all results(non-filtered results).
NOTE: I have tested the above mentioned URL through postman by making a get request and it gave out the filtered results perfectly.Why is the same not happening through my application code?plz help
getAsyncDataAction: debounce(function(name) {
if (!name.length) {
this.dataAction = [];
return;
}
this.isFetching = true;
api
.getSearchData(this.sessionData.key,`/action/?filter={id}like'%${name}%'`)
.then(response => {
this.dataAction = [];
response.forEach(item => {
this.dataAction.push(item);
});
console.log('action results are'+JSON.stringify(this.dataAction)) //displays all the results(non-filtered)
})
.catch(error => {
this.dataAction = [];
throw error;
})
.finally(() => {
this.isFetching = false;
});
}, 500),
api.js
import axios from 'axios';
const props = {
base_url: '/api/store',
search_url: '/api/entity/search',
cors_url: 'http://localhost',
oper_url: '/api'
};
axios.defaults.headers.get['Access-Control-Allow-Origin'] = props.cors_url;
axios.defaults.headers.post['Access-Control-Allow-Origin'] = props.cors_url;
axios.defaults.headers.patch['Access-Control-Allow-Origin'] = props.cors_url;
async function getSearchData(key, path) {
try {
console.log('inside getSearchData path value is'+path)
console.log('inside getSearchData and url for axios get is '+props.base_url + '/data' + path)
let response = await axios({
method: 'get',
url: props.base_url + '/data' + path,
headers: {'session_id': key}
});
if (response.status == 200) {
console.log(response.status);
}
return response.data;
} catch (err) {
console.error(err);
}
}
The problem is that you're not encoding the query string correctly. In particular, your % signs need to become %25
To do this, I highly recommend using the params options in Axios.
For example
async function getSearchData(key, path, params) { // 👈 added "params"
// snip
let response = await axios({
method: 'get',
url: `${props.base_url}/data${path}`,
params, // 👈 use "params" here
headers: {'session_id': key}
});
and call your function with
const params = {}
// check for empty or blank "name"
if (name.trim().length > 0) {
params.filter = `{id}like'%${name}%'`
}
api
.getSearchData(this.sessionData.key, '/action/', params)
Alternatively, encode the query parameter manually
const filter = encodeURIComponent(`{id}like'%${name}%'`)
const path = `/action/?filter=${filter}`
Which should produce something like
/action/?filter=%7Bid%7Dlike'%25TE%25'

How to passing result of http request inside async in ExpressJS?

I have below code
async send(user, data) {
const postData = {
'data': 'john',
'secret': 'secret'
};
const dataJson = JSON.stringify(postData);
const options = {
hostname: 'example.com',
path: '/send',
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Content-Length': dataJson.length
}
};
const req = https.request(options, (res) => {
let data = '';
console.log('Status Code:', res.statusCode);
res.on('data', (chunk) => {
data += chunk;
});
res.on('end', () => {
console.log('Body: ', JSON.parse(data));
});
}).on("error", (err) => {
console.log("Error: ", err.message);
});
req.write(dataJson);
req.end();
//---------------
let postResult = // HERE I WANT TO GET WHAT HTTP POST REQUESTED (e.g dataJson.body?)
//---------------
let result;
try {
result = await this.users.collection('users').updateOne(
{
_id: user
},
{
$set: {
// I WANT TO USE THAT HERE
data1 : postResult,
data2 : data2
}
},
{ maxTimeMS: consts.DB_MAX_TIME_USERS }
);
} catch (err) {
log.error('DB', 'UPDATEFAIL id=%s error=%s', user, err.message);
err.message = 'Database Error, failed to update user';
err.code = 'InternalDatabaseError';
throw err;
}
return { success: true };
}
How to get those data to outside variable?
I almost crazy about this, been searching on google and not found anything
I am using express and native-http to make http request, are there any native-curl maybe?
thank you very much for all the help
Your current code is using callback to retrieve result, so you can initiate data variable to outside callback function
let data = '';
const req = https.request(options, (res) => {
console.log('Status Code:', res.statusCode);
res.on('data', (chunk) => {
data += chunk;
});
res.on('end', () => {
console.log('Body: ', JSON.parse(data));
});
})
And also there are other easier way to make http request with nodejs. you can check axios that support Promise and async/await.
you can use syntax like this with axios
const response = await axios.get('/user?ID=12345');
way more easier.

Cannot get correct error from Axios

I have a doFetch function that handles all my api calls:
const doFetch = function(params){
...
// Make request using Axios. Axios is promise based.
return axios({
method: method,
url: baseUrl + url,
data: queryParams,
timeout: timeout,
headers: {
'Content-Type': contentType,
'Authorization': `bearer ${Auth.getToken()}` // set the authorization HTTP header
},
responseType: responseType
}).then((response) => {
if(typeof params.callback === "function"){
params.callback(response);
}
else {
return response;
}
}).catch((err) => {
if(typeof params.error === "function") {
if (err.response) {
params.error(err.response.data);
}
}
else{
if (err.response) {
return err.response.data;
}
else{
return err;
}
}
});
};
One such api call is returning a custom error like so (express server):
return res.status(400).json("There was an error on the server.");
The function that calls doFetch is saveUser:
saveUser(userObj).then((response) => {
console.log("No Error");
}).catch((error) => {
console.log("Error:", error);
});
The problem is that I am seeing No Error in the terminal, when I should only be expecting the error message to show. Any ideas?
I like to return promise exactly, to be sure that it does/returns what I want.
I don't like to rely on "promise"-s of 3rd parties.
So I would recommend You to wrap it inside of promise and resolve/reject responses/errors manually:
const doFetch = params => {
...
// Make request using Axios. Axios is promise based.
return new Promise((resolve, reject) => {
axios({
method: method,
url: baseUrl + url,
data: queryParams,
timeout: timeout,
headers: {
'Content-Type': contentType,
'Authorization': `Bearer ${Auth.getToken()}` // set the authorization HTTP header
},
responseType: responseType
})
.then((response) => {
console.info('doFetch:', response); // for debug purposes
if(typeof params.callback === "function"){
params.callback(response);
}
resolve(response);
})
.catch((err) => {
console.error('doFetch:', err); // for debug purposes
const error = (err.response) ? err.response.data : err;
if(typeof params.error === "function") {
params.error(error);
}
reject(error);
});
};
};

Doing a Timeout Error with Fetch - React Native

I have a user login function that is working. But, I want to incorporate a time out error for the fetch. Is there a way to set up a timer for 5 seconds or so that would stop trying to fetch after such a time? Otherwise, I just get a red screen after a while saying network error.
_userLogin() {
var value = this.refs.form.getValue();
if (value) {
// if validation fails, value will be null
if (!this.validateEmail(value.email)) {
// eslint-disable-next-line no-undef
Alert.alert('Enter a valid email');
} else {
fetch('http://51.64.34.134:5000/api/login', {
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
},
timeout: 5000,
body: JSON.stringify({
username: value.email,
password: value.password,
}),
})
.then((response) => response.json())
.then((responseData) => {
if (responseData.status == 'success') {
this._onValueChange(STORAGE_KEY, responseData.data.token);
Alert.alert('Login Success!');
this.props.navigator.push({name: 'StartScreen'});
} else if (responseData.status == 'error') {
Alert.alert('Login Error', responseData.message);
}
})
.done();
}
}
}
I have made a ES6 function that wraps ES fetch into a promise, here it is:
export async function fetchWithTimeout(url, options, timeout = 5000) {
return Promise.race([
fetch(url, options),
new Promise((_, reject) => setTimeout(() => reject(new Error('timeout')), timeout))
]);
}
Here is how to use it:
const requestInfo = {
method,
headers,
body,
};
const url = 'http://yoururl.edu.br'
let data = await fetchWithTimeout(url, requestInfo, 3000);
// Wrapper function for fetch
const fetchSomething = async () => {
let controller = new AbortController()
setTimeout(() => controller.abort(), 3000); // abort after 3 seconds
const resp = await fetch('some url', {signal: controller.signal});
const json = await resp.json();
if (!resp.ok) {
throw new Error(`HTTP error! status: ${resp.status}`);
}
return json;
}
// usage
try {
let jsonResp = await fetchSomthing();
console.log(jsonResp);
} catch (error) {
if (error.name === 'AbortError') {
console.log('Network Error');
} else {
console.log(error.message);
}
}
I think using AbortController is the recommended way to abort a fetch call. The code snippet above handles the following scenarios:
If network is good but HTTP returns an error status, the message "HTTP error! ..." will be logged.
If network is down, setTimeout would trigger the AbortController to abort fetch after three seconds. The message "Network Error" will be logged.
If network is good and HTTP response is good, the response JSON will be logged.
The documentation for using AbortController to abort fetch is here.
There is no standard way of handling this as a timeout option isn't defined in the official spec yet. There is an abort defined which you can use in conjunction with your own timeout and Promises. For example as seen here and here. I've copied the example code, but haven't tested it myself yet.
// Rough implementation. Untested.
function timeout(ms, promise) {
return new Promise(function(resolve, reject) {
setTimeout(function() {
reject(new Error("timeout"))
}, ms)
promise.then(resolve, reject)
})
}
timeout(1000, fetch('/hello')).then(function(response) {
// process response
}).catch(function(error) {
// might be a timeout error
})
Another option would be to modify the fetch.js module yourself to add a timeout that calls abort as seen here.
This is what I did to go around it:
(This is the "generic" function I use to make all calls on my app)
I created a timeout function, that will be triggered unless it is cleared before, then I clear this timeout on server response
const doFetch = (url, callback, data) => {
//... creating config obj here (not relevant for this answer)
var wasServerTimeout = false;
var timeout = setTimeout(() => {
wasServerTimeout = true;
alert('Time Out');
}, 3000);
fetch(HOST + url, config)
.then((response) => {
timeout && clearTimeout(timeout); //If everything is ok, clear the timeout
if (!wasServerTimeout) {
return response.json();
}
})
.then((response) => {
callback && callback(response.data || response);
})
.catch((err) => {
//If something goes wrong, clear the timeout
timeout && clearTimeout(timeout);
if (!wasServerTimeout) {
//Error logic here
}
});
};
I solved this problem by using a race between 2 promises, written as a wrapper around fetch. In my case I expect the request to return json so also added that. Maybe there is a better solution, but this works correctly for me!
The wrapper returns a promise which will resolve as long as there are no code errors.
You can check the result.status for 'success' and read json data from result.data. In case of error you can read the exact error in result.data, and display it or log it somewhere. This way you always know what went wrong!
var yourFetchWrapperFunction = function (
method,
url,
headers,
body,
timeout = 5000,
) {
var timeoutPromise = new Promise(function (resolve, reject) {
setTimeout(resolve, timeout, {
status: 'error',
code: 666,
data:
'Verbinding met de cloud kon niet tot stand gebracht worden: Timeout.',
});
});
return Promise.race([
timeoutPromise,
fetch(connectionType + '://' + url, {
method: method,
headers: headers,
body: body,
}),
])
.then(
(result) => {
var Status = result.status;
return result
.json()
.then(
function (data) {
if (Status === 200 || Status === 0) {
return {status: 'success', code: Status, data: data};
} else {
return {
status: 'error',
code: Status,
data: 'Error (' + data.status_code + '): ' + data.message,
};
}
},
function (response) {
return {
status: 'error',
code: Status,
data: 'json promise failed' + response,
};
},
)
.catch((error) => {
return {status: 'error', code: 666, data: 'no json response'};
});
},
function (error) {
return {status: 'error', code: 666, data: 'connection timed out'};
},
)
.catch((error) => {
return {status: 'error', code: 666, data: 'connection timed out'};
});
};
let controller = new AbortController()
setTimeout( () => {
controller.abort()
}, 10000); // 10,000 means 10 seconds
return fetch(url, {
method: 'POST',
headers: headers,
body: JSON.stringify(param),
signal: controller.signal
})
I may be late but i made a code which is 100% working to timeout an API request using fetch.
fetch_timeout(url, options) {
let timeout = 1000;
let timeout_err = {
ok: false,
status: 408,
};
return new Promise(function (resolve, reject) {
fetch(url, options)
.then(resolve, reject)
.catch(() => {
alert('timeout.');
});
setTimeout(reject.bind(null, timeout_err), timeout);
});
}
You just need to pass the api-endpoint to the url and body to the options parameter.