Fetch: reject promise and catch the error if status is not OK?
Fetch promises only reject with a TypeError when a network error occurs. Since 4xx and 5xx responses aren't network errors, there's nothing to catch. You'll need to throw an error yourself to use Promise#catch
.
A fetch Response conveniently supplies an ok
, which tells you whether the request succeeded. Something like this should do the trick:
fetch(url).then((response) => {
if (response.ok) {
return response.json();
}
throw new Error('Something went wrong');
})
.then((responseJson) => {
// Do something with the response
})
.catch((error) => {
console.log(error)
});
How to catch the error when making fetch api request?
If you are using async await you shouldnt have to chain on .thens like you are resolving a promise.
I adjusted your code and wrapped it in a try/catch, the try/catch error will handle an error from a non response however you will need to check your server response for errors itself
async loginUser() {
try {
let response = await this._service.LoginUser(this.user)
// Check your response for error this may not be response.error
if (response.error) {
// Handle error
alert(error)
} else {
// Navigate on success
this._router.navigate(['/mainpage'])
}
} catch (err) {
alert(err)
}
}
Within a fetch() Promise, how to .catch server errors messages when status is 4xx or 5xx?
Try response.text()
instead of response.json()
when the status code is 400
or 500
.
In my experience, the error messages are typically returned by the text
callback.
See this answer to a similar question.
Edit:
Added the following code, suggested by OP.
.then((response) => {
if (response.ok) {
return response.json();
}
else {
return response.text()
.then((text) => {
throw(text);
// if the error is an object and you just want to display some elements:
throw(JSON.parse(text));
});
}
})
.catch((err) => {
// in case you want to log the error
console.log("somesite: ", err));
return new Error("somesite: " + err);
});
promise catch: how to know if the error comes from promise rejection or from the then statement
then
accepts two parameters¹: A function to call on fulfillment, and another to call on rejection. So you can handle the initial rejection earlier:
fetch(/*...*/)
.then(
// Fulfillment handler
(response) => {
/*...*/
},
// Rejection handler for `fetch` promise
(error) => {
/*...*/
}
)
.catch((error) => {
// This rejection handler only sees errors not handled above
});
The first rejection handler (in the then
call) is only called for rejections of the promise from fetch
, not rejections caused by errors in the fulfillment handler.
The second rejection handler (in the catch
call) is called for rejections caused by errors (or rejected promises) from the handlers that come before it (either fulfillment or rejection); it doesn't get called if the original promise is rejected (but it may well get called if the first rejection handler throws an error or returns a promise that is/will be rejected).
So in those cases where you care, you can handle it closer to the source.
Note that all rejection handlers that don't either throw an error or return a promise that is/will be rejected convert rejection (of the original promise) into fulfillment (of the one from then
/catch
). That can matter for downstream then
handlers.
A key thing to understanding this is to remember that then
(and its wrappers catch
and finally
) return a new promise. That's why:
aPromise.then(onFulfilled).catch(onRejected);
is different from
aPromise.then(onFulfilled, onRejected);
The first one hooks up a fulfillment handler to aPromise
, and then hooks up a rejection handler to the promise then
returns (which means the rejection handler will be called if aPromise
rejects or if the fulfillment handler throws an error or returns a promise that rejects). In contrast, the second one only hooks up handlers on aPromise
, so errors/rejections from the fulfillment handler do not trigger the rejection handler.
¹ In fact, .catch(fn)
is just a wrapper for .then(undefined, fn)
. :-) spec link
Failing fetch in a Promise.all not catching error
This call:
.catch(error => console.log(error))
...will return a fulfilled promise, not a rejected one. Whenever you treat a rejection and you want it to bubble up as a rejection, you should explicitly do that:
.catch(error => {
console.log(error);
throw error; // cascade...
})
By the way, this has no effect at all
Promise.reject('Error while fetching data');
... as you don't do anything with this newly created, rejected promise.
Catching a fetch error
APIwithoutcatch
is an async function
- it doesn't throw an exception but rather will reject the promise that it returns. You need to wait for the promise, either with then
or await
syntax (just like you did await
the fetch
within APIwithcatch
):
async function API() {
return fetch("http://wwww.example.com/user.json");
}
function callAPI() {
try {
await API();
} catch (e) {
console.log(e);
}
}
callAPI();
Related Topics
iPad Web App: Detect Virtual Keyboard Using JavaScript in Safari
A Cors Post Request Works from Plain JavaScript, But Why Not with Jquery
How to Call Loading Function with React Useeffect Only Once
Rails - Could Not Find a JavaScript Runtime
How to Loop Through All Dom Elements on a Page
How to Find First Element of Array Matching a Boolean Condition in JavaScript
Selected Text Event Trigger in JavaScript
Check for Special Characters in String
What Do Curly Braces Inside of Function Parameter Lists Do in Es6
How to Check in JavaScript If One Element Is Contained Within Another
JavaScript Hard Refresh of Current Page
Generate PDF from HTML Using PDFmake in Angularjs