javascript fetch does not catch 404 error - javascript

I have an app with uses a fetch to retrieve information from a 3rd party API. I am calling the API via cors-anywhere-herokuapp.com. When I call the API with valid data, I am able to retrieve the API response and pick up the data I need to pick up. When I call the API with invalid data, the API returns a 404 server error. I am forcing invalid data so I can code to catch this situation. My problem appears to be that the fetch does not catch the 404 error. I have tried coding to inspect the return.status but to no avail. I tried testing return.ok and that didn't work either. This is the code I am executing:
function showProduct(barcode) {
let url = "https://cors-anywhere.herokuapp.com/http://api.barcodelookup.com/v2/products?barcode=" + barcode + "&key=mj1pm32ylcctxj1byaia85n9dk2d4i";
url = "https://cors-anywhere.herokuapp.com/http://api.barcodelookup.com/v2/products?barcode=5000159459211&key=mj1pm32ylcctxj1byaia85n9dk2d4i";
const options = { method: 'GET' };
fetch( url, options)
.then(function(response) {
return response.json();
})
.then(function(myJson) {
if (myJson == undefined)
{
console.log("fetch failed")
}
else
{
//inspect the data that the WebAPI returned
document.getElementById("showScanner").style.visibility = "hidden";
document.getElementById("scanner-container").style.visibility = "hidden";
document.getElementById("showProductDiv").style.visibility = "visible";
document.getElementById("productManufacturer").innerHTML = myJson.products[0].manufacturer;
document.getElementById("productName").innerHTML = myJson.products[0].product_name;
document.getElementById("productDescription").innerHTML = myJson.products[0].description;
Quagga.stop();
}
});
}
and this is what I see in the debugger when I execute the code
When I look at the debugger network tab, and click on Headers, I see this:
So, my question is, how do I capture the status code?

According to the documentation on fetch's response, you should be able to testthe status code of the response that fetch's Promise resolves to using response.status.
Note that although it's unintuitive, the Promise fetch returns only rejects when there's a connection error. If the connection succeeds and there's a response, this promise will resolve with the response, even if the status code is non-200.

Related

FetchError: request to url failed, reason ECONNREFUSED crashes server despite try catch being in place

The problem
FetchError: request to https://direct.faforever.com/wp-json/wp/v2/posts/?per_page=10&_embed&_fields=content.rendered,categories&categories=638 failed, reason: connect ECONNREFUSED
I'm doing some API calls for a website using fetch. Usually there are no issues, when a request "fails" usually the catch error gets it and my website continues to run. However, when the server that hosts the API calls is down/off, my fetch API calls crash the website entirely (despite being on a try catch loop).
As far as I'm concerned, shouldnt the catch block "catch" the error and continue to the next call? Why does it crash everything?
My wanted solution
For the website to just move on to the next fetch call / just catch the error and try again when the function is called again (rather than crashing the entire website).
The code
Here is an example of my fetch API call (process.env.WP_URL is = https:direct.faforever.com )
async function getTournamentNews() {
try {
let response = await fetch(`${process.env.WP_URL}/wp-json/wp/v2/posts/?per_page=10&_embed&_fields=content.rendered,categories&categories=638`);
let data = await response.json();
//Now we get a js array rather than a js object. Otherwise we can't sort it out.
let dataObjectToArray = Object.values(data);
let sortedData = dataObjectToArray.map(item => ({
content: item.content.rendered,
category: item.categories
}));
let clientNewsData = sortedData.filter(article => article.category[1] !== 284);
return await clientNewsData;
} catch (e) {
console.log(e);
return null;
}
}
Here's the whole code (this whole thing is being called by express.js in line 246 (the extractor file).
Extractor / Fetch API Calls file
https://github.com/FAForever/website/blob/New-Frontend/scripts/extractor.js
Express.js file in line 246
https://github.com/FAForever/website/blob/New-Frontend/express.js#:~:text=//%20Run%20scripts%20initially%20on%20startup

readableStream is locked while using .json()

everyone!
I got a problem: I'm trying to validate registration form. Totally, it works ok, but I need to validate form via server. In my case, for example, I need to figure out if email is already taken.
I tried to fetch and async/await syntax, but problem is still the same:
DOMException: "The operation was aborted. "
The way I understand it right now is readableStream (what actual response body is) is locked. So the wrong error is thrown, and I cannot get server response.
try {
const response = await fetch(options.url, options.requestOptions);
const body = await response.json();
if (options.modifyDataCallback instanceof Function) {
body.data = options.modifyDataCallback(body.data);
}
return body.data;
} catch (error) {
throw error;
}
How do I see the solution? I send request and recieve some server error like
code: email_in_use
message: Email '...' is already in use.
Then I need to throw error and catch it in other place in order to show corresponding error message to client.
In browsers network tab I do receive what I want to receive, but can't get the same JSON-response in my code.
Google chrome provided more information: net::ERR_HTTP2_PROTOCOL_ERROR 200.
And the problem was on backend. It is written in C# and API method returned Task. The problem was solved by adding async/await for this method.

Why do I get "Fetch failed loading" when it actually worked?

I use the following code to POST the users position to my own backend-service via the Fetch API:
window.onload = () => {
let getPosition = (options) => {
return new Promise((resolve, reject) => {
navigator.geolocation.getCurrentPosition(resolve, reject, options);
});
};
getPosition().then(pos => {
const data = new FormData();
data.append('latitude', String(pos.coords.latitude));
data.append('longitude', String(pos.coords.longitude));
fetch('/', { // <--- error is thrown in this line
method: 'POST',
body: data
}).then(response => {
if (!response.ok) {
throw Error('Data sent - Network response NOT OK');
} else {
console.log('Data sent - Network response OK')
}
});
});
};
This works flawlessly and the backend-service sends back a positive empty response. Data sent - Network response OK is logged in the browser's console and everything is fine except that immediately after, this is logged:
How come I get a Fetch failed loading: POST even though the POST succeeded, the response is OK and the status code in the Chrome network tab is 200 OK? Is there something wrong with my code?
I had the same behaviour that you were seeing.
My server responded to the POST request with a 204 (Empty Response) and an empty (Content-Length=0) response.
I tried changing that to just respond with a "ok" message instead (edit: actually just returning the created object now) and the fetch error log disappeared.
It seems to me that fetch (at least in Chrome) erroneously logs "Fetch Failed" when the response body is empty, even if the request was successful.
This happens because you don't read the empty response body. I noticed this, because Django triggers a broken pipe error on the server side. To fix this, just read the empty body out.
async function fetchSomething() {
const response = await fetch(url, {
method: 'POST'
})
await response.text()
return response.ok
}

How can i send data through an API to other servers only using Nodejs and Express?

I'm new to NodeJS and I am currently working on getting an API working. Currently running is Express for that purpose and i really would like to stick to express to solve it.
My goal is to let other people send me their data through links (Example would be: http://localhost:1000/api/?product=test) so i can just grab them with a simple 'var productname = req.param('product'); That part works just fine.
But i would like to simply call a method to send data from my server, meaning i would like to trigger sending the data with a function and then send the data as a link to another server. (Example would be to http://google.com/search?q=test)
I can't seem to get it to work even if i directly work with the documentation from express: https://nodejs.org/api/http.html#http_http_get_url_options_callback
Could anyone point me in the right direction?
If i try the code snippet below, I'm not even getting a console.log.
My current code attempt is:
// testing purpose to call the method and get a console log
sendServerUpdates('chair');
function sendServerUpdates(product){
url = 'google.com/';
app.get(url + 'search', (res) => {
const {statusCode} = res;
const contentType = res.headers['content-type'];
let error;
if (statusCode !== 200) {
error = new Error('Request Failed.\n' + `Status Code:
${statusCode}`);
} else if (!/^application\/json/.test(contentType)) {
error = new Error('Invalid content-type.\n' + `Expected
application/json but received ${contentType}`);
}
if (error) {
console.error(error.message);
// Consume response data to free up memory
res.resume();
return;
}
// Information for me that the system is sending a message
console.log('sending update');
// sending (if its working) the parameter product
res.status(200).send(product);
})
}
}

Is there really no way to get the response body from a failed js fetch request?

The new js fetch API fails the promise if the request fails (400):
fetch(uri).catch(function(err) {
console.log(err);
});
Is there really no way to get the response body when this happens? e.g. to check an error code.
EDIT: I've created a js fiddle: https://jsfiddle.net/4x4xLwqo/ that calls this mockbin endpoint: http://mockbin.org/bin/d87acbb0-526e-4d66-aea4-b827d9c35031/view
EDIT 2: updated jsfiddle to use a better endpoint: https://jsfiddle.net/4x4xLwqo/2/
fetch won't go into catch if it encounters a HTTP error. You can handle that with a regular then.
From MDN:
A fetch() promise will reject with a TypeError when a network error is encountered, although this usually means permission issues or similar — a 404 does not constitute a network error, for example. An accurate check for a successful fetch() would include checking that the promise resolved, then checking that the Response.ok property has a value of true.
And an accompanying example, from MDN as well:
fetch('flowers.jpg').then(function(response) {
if(response.ok) {
response.blob().then(function(myBlob) {
var objectURL = URL.createObjectURL(myBlob);
myImage.src = objectURL;
});
} else {
console.log('Network response was not ok.');
}
})
.catch(function(error) {
console.log('There has been a problem with your fetch operation: ' + error.message);
});

Categories