Handle unreachable server when using Fetch API with react native - javascript

In my react native app, the server is specified by the user. Although I put some control on the "url" field, sometimes the user put an url which simply does not exist.
Then, I got a TypeError:
Network request failed
How can I handle these case in my code?
Thank you

You should handle the error case in .then for fetch API.
For example:
fetch('...URL')
.then(
(response) => {
console.log('success',response)
},
(err) => {
console.log('error',err)
}
);

Related

Catching Error With Custom Rest API For FireStore Javascript

I have been watching a tutorial on making a Rest API for Firestore which appears to work but I cannot figure out how to catch an error.
The code below basically uses an end point to retrieve a document id from the firestore database.
The client uses javascript fetch to call the API.
I am trying to workout how to return something back to the client from the API if the document id is not there. I thought I might get a 404 status returned but I always get status 200.
This is the API code I used
app.get("/api/read/:id", (req, res) => {
(async () => {
try {
const document = db.collection("users").doc(req.params.id);
let product = await document.get();
let response = product.data();
return res.status(200).send(response);
} catch (error) {
console.log(error);
return res.status(500).send(error);
}
})();
})
I'm fairly certain that the 404 message is for the server itself not being found (though I do need to brush up on my error codes).
However, if you're looking to check to see if a document exists there's a command specifically for that demonstrated in the examples in the firebase docs

Api is not fetching in reactJs

I am trying to fetch food by its key. In postman api is working fine but is the forntend it has no response.
backend code
app.get('/foods/:key', (req, res) => {
foodsCollection.find({ key: req.params.key }).toArray((err, documents) => {
res.send(documents[0])
})
})
frontend code
const { key } = useParams()
const [foodById, setFoodById] = useState({})
useEffect(() => {
fetch(`http://localhost:5000/foods/${key}`)
.then((res) => res.json())
.then((data) => {
setFoodById(data)
})
}, [key])
Although you've added some images above, the most important is missing, namely, what are the Browser's Developer Tools stating the problem is. You should see some message in the Console tab, as well as in the Network tab for that particular request, if it is indeed being made. Until anyone sees this, it will be very difficult to help in fixing your problem.
If your not already, I suggest scaffolding any react app with create-react-app (CRA). This will give you a working app to start from. You can ignore CORS related issues in development, if using CRA, by adding "proxy": "http://localhost:5000", to your package.json file, see here for more on this method, but remember, this is only works for local development. You can also start Chrome to ignore Web Security by running it with the --disable-web-security flag e.g. chromium --disable-web-security, but that isn't a great idea really, more a way to quickly determine if you are having CORS problems, as Chrome masks some problems as CORS related, when in fact they aren't.
I'd also suggest changing your fetch code to use await, so instead you'd have:
const response = await fetch(`http://localhost:5000/foods/${key}`);
if (!response.ok) {
console.error(`Error message: ${response.statusText} ${response.status}`);
}
const result = response.json();
console.log(result);
This isn't necessary, but I've always found it way easier to read than the then/catch/finally method.
Reason for error
You need to stringify an object before sending it to the client with the JSON.stringify() method. When we exchange data to/from a web server, it must be a string.
Solution:
Proper way to send response to the client would to wrap the entire API in a try-catch block and explicitly specify the HTTP Status Code along with the stringified data in every response.
Note: Although 500 status code is used for error handling, you should choose one as per the use case.
app.get('/foods/:key', (req, res) => {
try {
/*
rest of the code
*/
foodsCollection.find({ key: req.params.key }).toArray((err, documents) => {
if (err) {
// 500 stands for internal server error
return res.status(500).send(JSON.stringify('Here goes a meaningful error message!'));
}
// 200 stands for success
res.status(200).send(JSON.stringify(documents[0]));
});
/*
rest of the code
*/
} catch (error) {
// 500 stands for internal server error
res.status(500).send(JSON.stringify('Here goes another meaningful error message!'));
}
})
The problem is that you haven't set the CORS headers of response in your backend code. and you are using different ports in your backend and frontend (5000 & 3000) so the Same Origin Policy disallows reading the remote resource, indicating that the request was blocked due to violating the CORS security rules.
you've to set the CORS headers.
you can install the CORS npm package and follow it's instructions to resolve the issue like this:
var express = require('express')
var cors = require('cors')
var app = express()
app.use(cors())
.
.
.
And one other issue that I'm seeing is that you've put the react-router default route before your specified path. so move the <route path="*"> after <route path="/foods/:key">

Reading error message returned by postman in react native app

I have an api used for login in my react native app. The api is implemented and working as its supposed to. But the issue is that if the user enters wrong email or password m not receiving the error message in the response in the application. While if i test the api manually in postman it returns the error message required. i tried making a transformer for the error response but m not knowing how to implement it or use it. I'm using fetch to call my apis.
return fetch(fullUrl, requestParameters)
.then((response) => {
if(response.ok) {
return response.headers.get("content-type") === "application/json" ? response.json() : null
} else {
errorrr = ErrorTransformer.backward(response)
console.log("Error: ", errorrr)
}
And below is the tranformer made for the error response
import {createTransformer} from './Transformer';
const ErrorTransform ={
o:[
['message','message'],
['code','code'],
]
}
export default createTransformer(ErrorTransform)
And below is the response returned from postman when wrong info are entered
{
"message": "error",
"code": 1
}
You can check on the basis of the response code. I'll suggest using the Axios library. Axios NPM
After a lot of trials, i figured that the postman response when the user enters wrong email or password is a regular response object, it’s not an error. So its handling should be like a regular response. But what remained as an obstacle is to tell apart when i have a success response with the info returned, or when i have the error object returned. I solved this issue by combining the error transformer with the login transformer, and its handling it perfectly.

How can I get my fetch error to show an http status code?

I have a react component and I'm making a network call to set the state. Eventually I want to pass this down to other child components, but just getting the plumbing to work at the moment.
I'm trying to catch errors correctly when calling out to my backend (an express server in the app). I attempted to force an error by fetching data from an endpoint that doesn't exist. This should throw a 404 since it doesn't exist, right? How can I get that error surfaced in the catch statement? Right now my error is SyntaxError: Unexpected token < in JSON at position 0 at eval (app.js:61)
export default class App extends Component {
constructor(props) {
super(props);
this.state = {
data: null
};
}
componentDidMount() {
fetch('/api/wrong_endpoint').then((data) => {
return data.json();
}).then((body) => {
this.setState({data: body})
}).catch(err => console.log(err));
}
render() {
console.log('logging the states');
console.log(this.state.data);
return (
<div>
<ContactList />
<ContactDetail />
<AddContactModal />
</div>
);
}
}
I'll try to go step by step
fetch method doesn't throw an error even if you get the 4xx or 5xx response codes. Please read about the Fetch API carefully, I believe you can find a lot of interesting you don't know about it.
You can easily check the response status as follows (please read about the Response object and its methods/properties):
fetch('/api/wrong_endpoint').then((response) => {
console.log('status code', response.status)
})
It's hard to say if your server really returns 404 code because I don't know your express setup. If you set some fallback handler like app.get('*', ...) then it might as well return 200 success code. You can check the response status and its body in devTools of the browser. But I believe it's better if you configure at least your /api router to return 404 error if the requested /api/... route isn't found.
What I'm really sure of is that your server returns some HTML layout in the response. And you try to parse it as JSON string via data.json() and of course you get the syntax error since it's not JSON (html layout starts with < symbol hence the error: SyntaxError: Unexpected token <)
Generally, if you are using the fetch API, errors 40x and 50x will not go into the subsequent blocks, as the promise from fetch only rejects network errors (not HTTP errors or anything else). Therefore, requesting for data from an 'incorrect' endpoint will be handled within the first then block.
I would recommend you to use check your http response body based on the Response.Ok property. Successful responses will be handled within that condition, whereas any other responses (ok: false) will be handled on the other statement.
fetch('/api/wrong_endpoint')
.then(response => {
console.log(response) // full response body
console.log(response.status); // get only the response.status
if (!response.ok) {
// http errors 40x and 50x will go into this statement
// do something to handle it
} else if (response.ok) {
// handles status code 200
}
})
.then(
// ...

Can't fetch data, CORS issue, trying to hack it with JSONP, still not working

I'm trying to fetch data from http://www.recipepuppy.com/api/?q=onion&p=1. (Sample query)
It works in a browser, but I was trying to fetch it inside my React app and I'm encountering “No 'Access-Control-Allow-Origin' header is present on the requested resource error.
So I changed my strategy and now I'm trying to use JSONP (https://github.com/mzabriskie/axios/blob/master/COOKBOOK.md#jsonp).
But I can't make it work. I'm getting this error all the time. Can someone please help me with my issue?
Error:
Uncaught ReferenceError: jp0 is not defined
at ?q=onion&p=1&callback=__jp0:1
My Code:
import jsonp from 'jsonp'
export const FETCH_RECIPES = 'FETCH_RECIPE'
export const SHOW_INFO = 'SHOW_INFO'
export function fetchRecipes (searchTermToDOoooooooooo) {
const request = jsonp('http://www.recipepuppy.com/api/?q=onion&p=1', null, function (err, data) {
if (err) {
console.error(err.message)
} else {
console.log(data)
}
})
return (dispatch) => {
/*
request.then(({ data: data1 }) => {
dispatch({ type: FETCH_RECIPES, payload: data1 })
})
*/
}
}
export function showInfo (info) {
return {
type: SHOW_INFO,
payload: info
}
}
How that error looks in dev tools:
You can't do it with client-only code, at least not with JSONP+Axios (Axios doesn't (natively) support JSONP; the "jsonp" library is different from Axios), because it's the server you're getting information from that's in violation of the cross-origin rules. In this case, it's Recipe Puppy that isn't set up for Access-Control-Allow-Origin headers.
One option is to use a server-side proxy, as #Pointy mentions.
Your flow would then shift to:
Client calls server-side proxy for information.
Proxy calls Recipe Puppy's API and translates or passes through information as needed.
Proxy relays that information to the client-side code for further processing.
As for your current shift to jsonp, it appears the jsonp library is not exporting jp0 properly for some reason. This could be an error with your build tool. You'll want to double-check your setup and make sure your build tool is picking up the jsonp library and actually putting it into the compiled source.

Categories