node-fetch HTTP Errors not being caught - javascript

I am having some problems with catching nodejs fetch exceptions
What I am expecting to happen is:
HTTP error of some sort occurs in my fetch call
CheckResponseStatus function runs and an error an error is thrown with the server error status and text
This error is caught and the ServerError function runs which (just for testing) will just print the error to the console.
However, the error printed to the console is:
Cannot connect to Server. Check you are using the correct IP Address and the server is running.
FetchError: request to http://localhost:3689/api/outputs failed, reason: connect ECONNREFUSED 127.0.0.1:3689
This is implying that the error I have thrown is not being caught, some default fetch error is being caught, and CheckResponseStatus is not being run.
My code is below
Node-Fetch HTTP Request:
async function getStatus(serverip,serverport){
return await fetch(`http://${serverip}:${serverport}/api/outputs`)
.then(this.checkResponseStatus)
.then(res => res.json())
.catch((err) => this.ServerError(err));
}
CheckResponseStatus Function:
checkResponseStatus(res) {
if(res.ok){
return res
}
//will add elseif's here for different HTTP errors
else {
throw new Error(`The HTTP status of the response: ${res.status} (${res.statusText})`);
}
}
ServerError Function:
ServerError(err){
console.log('Cannot connect to Server. Check you are using the correct IP Address and the server is running.');
console.log(err);
}
Thanks for any suggestions or help.

If fetch is unable to connect to the remote server, it will reject. In your code, checkResponseStatus is never called because fetch is never able to get a response; the first two .then blocks are skipped because fetch rejected, so execution goes directly to the .catch block.
If you want network errors to run through checkResponseStatus, you can add a second .catch before the first .then and format the error into a "response":
fetch(`http://${serverip}:${serverport}/api/outputs`)
.catch(err => {
// return a mock failed response for checkResponseStatus to handle
return {
ok: false,
status: -1,
statusText: 'Network Failure',
};
})
.then(this.checkResponseStatus)
.then(res => res.json())
.catch((err) => this.ServerError(err));
However, I believe your code is currently running how I would expect it to - a network failure skips checkResponseStatus, which makes sense because there's no real response to check.

Related

Why does a GET request with fetch API log a server response error message into the browser console?

I am using the fetch-API to send a GET request to a Spring Boot backend. The request looks somewhat like this:
const response = await fetch(url);
if (response.status === 200) {
// do something
} else {
response.json().then(response => console.log(response));
}
In case that I send a valid request, i.e. the url passed into fetch() is valid, everything works fine. In case that I pass an invalid url into fetch(), however, two things appear to be happenning:
A serer response message is thrown:
My Spring Boot backend return a ResponseEntity with a custom error message as body. This error message is logged inside the else-block of the above code snippet:
While I do expect the second point to be happenning, I cannot explain the first. I don't understand why this server-response error is logged into my browser console. I do have a few catch-blocks inside my code, something like:
const response = await fetch(url).catch(error => console.log(error));
As far as I know, however, fetch only throws an error if a network connection error occurred or similar. A response code not equal to 200 does not result in fetch throwing an error. So, as I said, I don't know where this error message comes from and I was hoping that somebody does, maybe it is something generic to the fetch API that I just don't know?
I recommend using "try catch" to better capture errors.
If the response is positive and it's a json, use a "then" after the fetch.
try {
const response = await fetch(url).then(res => res.json());
// do something
} catch (e) {
console.error(e);
}
If you're getting a 400 error, check the api documentation to see if you're passing the parameter incorrectly. or if that is not the route

How to handel "net::ERR_QUIC_PROTOCOL_ERROR 200" in a fetch?

By simulating a Lie-Fi connection I noticed that I get an (net::ERR_QUIC_PROTOCOL_ERROR) error that didn't triggered the catch part of the fetch statement.
The reason that the fetch wasn't triggered is that the status code of the network request returned 200. Why is this Error OK (200)?.
But the main question is how can I detect and handle these errors?
This question gets more interesting in case the fetch is part of a fetch event handel of a serviceworker. For when the serviceworker tries to fetch something from the internet and if that isn't possible returns a result from the cache. These errors however will not be seen as an error and therefore the data from the cache will not be returned. As a user I then will not get the offline experience I would expect.
// please set Network Throttling to Lie-Fi (1kbit/s up&down)
const timeoutSimulation = () => {
return fetch('https://thispersondoesnotexist.com/image', {mode: 'no-cors'})
.then((response) => {
console.log(`would not expect to see this message, due to the net error`);
return response;
})
.catch((error) => {
console.log('expect this error to be shown', error);
})
}

API response 404 not found Handling

I am working on a project with API. API response is 404 not found. I need to handle this status code without a new page. I want to add an window.confirm("not found"). However, I couldnt do that, because when API says 404 there is no response so I couldn't check the response. How can I do that without using new page? How can I handle that? Here is my response code:
const response = await instance.get(`?q=${q}&appid=${appid}`);
if (!response) {
console.log("ceren");
}
It never prints "ceren". I tried response ==="", response ===null, response.data===null, and so on
The response object is never null. It's an object that, along with many other keys, includes the status. Moreover, if the request fails, it will throw an error (due to the await, though outside of this function it will be a Promise rejection), so you can just catch that:
return instance.get(`?q=${q}&appid=${appid}`).then(/*...*/).catch((error) => console.log('Request failed!'));
Or, if you must use an await:
try {
const response = await instance.get(`?q=${q}&appid=${appid}`);
} catch (error) {
console.log('Request failed!');
}

Get Axios frontend Promise to receive errors msg from Rails backend

In Rails I'm returning:
render json: { errors: e.response.body.errors }, status: 400
In JavaScript I'm using Axios:
axios.patch('/settings/account', {}, {params: {...
} })
.then((e)=> {
...
console.log('submitted')
})
.catch(function (error, res) {
// only get error that gives 400, but not error msg here, res isn't here
console.log(error);
});
How do I get the e.response.body.errors on my frontend?
Axios reject promises if the server response http status code is anything but 2xx. I see you are sending an error response from the server, but are you sending this response through a http error status? If you arent, the error isnt an error to axios, so the error would show in the "then()" hook, since the promise is resolved.
If you are, then you should see the error whithin error.response.data

How do I get the full error message from my Node and Express server on the client side?

I have an express route that returns a 400 status and an error message. I want to alert the full error message on the client-side, but the alert only says "Object object" when I alert it. I inspected that object and I don't see the full error message that I see logged to my terminal from the server.
On the server the error message says, "djhbf is not defined" because I typed in some random characters to throw an error message. On the client-side, the object has some properties, but none of them contain the error message "djhbf is not defined". The closest thing to an error message is, "status-text: bad request". How do I retrieve the actual error message "djhbf is not defined" on the client-side?
Here is my server.js code which sends the error message in its catch block of a promise:
app.post('/sendEmails', function(req, res, next) {
axios.get(FEED_URL)
.then(data => {
let jobs = data.data.jobs;
fetchClients(jobs, 'email').then(() => {
res.sendStatus(200);
})
.catch((err) => {
console.log(err);
res.status(400).json(err);
})
})
.catch(error => {
console.log(error);
});
});
Here is the client-side code which alerts the error:
sendEmails() {
axios.post("/sendEmails")
.then(res => {
this.setState({
emailsSent: true,
smsSent: false
});
})
.catch((err) => {
console.log(err);
alert(err);
});
}
Updated
This is not an express issue. axios decorates the error object. You just need to change your client side console.log to this: console.log(err.response.data);
You will also need to update your server side logic since you are using axios on both sides. Try res.status(400).json({msg: 'There was a problem with your request'});
If that works you'll just need to drill down in the err object on the server side to see what you want to send back to the client.
See the Error Handling section of the axios docs.

Categories

Resources