fetch: Reject promise with JSON error object
// This does not work, since the Promise returned by `json()` is never fulfilled
return Promise.reject(resp.json());
Well, the resp.json
promise will be fulfilled, only Promise.reject
doesn't wait for it and immediately rejects with a promise.
I'll assume that you rather want to do the following:
fetch(url).then((resp) => {
let json = resp.json(); // there's always a body
if (resp.status >= 200 && resp.status < 300) {
return json;
} else {
return json.then(Promise.reject.bind(Promise));
}
})
(or, written explicitly)
return json.then(err => {throw err;});
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)
});
Promise reject as json
.then((response)=>{}) is called when the promise end up succesfully (with resolve() function) so you shouldn't call resolve function in then() function.
.catch((err)=>{}) is called when the promise fails (with reject()function )
what you need to do is handle successful responses in then and handle fails in catch.
.then(response=> {
if (response.ok) {
return response.json().then(user=> {
console.log(user);
AsyncStorage.setItem('auth.token', user.api_token);
AsyncStorage.setItem('user_name', user.user.name);
AsyncStorage.setItem('user_email', user.user.email);
})
} else {
if (response.status == 422) {
return response.json();
} else {
return {"email": ["Technical problem, try later"]}
}
}
} .catch(function (err) {
return ({"email": ["Technische fout. Probeer het opnieuw"]});
});
If you want to control resolve and rejects you can use 'request' instead of fetch
var request = require('request');
function getUserData() {
return new Promise(function(resolve, reject) {
request('http://......', function(error, response, body) {
if (error) return reject(error);
resolve(body);
});
});
}
async function main() {
try {
var response= await getUserData();
console.log(response);
} catch(error) {
console.error(error);
}
}
take a look at this blog
https://www.twilio.com/blog/2015/10/asyncawait-the-hero-javascript-deserved.html
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);
});
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.
Rejecting promise when using fetch
If you want to reject from success callback you need to do it explicitly by either returning rejected promise, e.g. return Promise.reject('error occurred');
or by throwing.
Additionally, you should not abuse Promise
constructor in your case since fetch
already returns promise object:
function a(url, config) {
if (!config)
config = {};
config = Object.assign(config, {
headers: {
'content-type': 'application/json;charset=utf-8'
}
});
return fetch(url, config).then(
function(res) {
if (res.status == 200 && res.ok) {
console.log("Promise resolved")
return res.json();
}
console.log("Promise rejected");
throw 'promise rejected';
},
function(rej) {
console.log("promise rejected");
throw 'promise rejected';
}
);
}
fetch api throws uncaught in promise error
Note: When this answer was posted, the question didn't have the return
. The OP added it afterward, claiming it was in their original code. But they also accepted the answer, so something below must have helped... :-)
apiRequest
needs to return the promise chain. Right now, it doesn't, so calling it returns undefined.
const apiRequest = (url) => {
return fetch(url) // *** Note: Added `url` here
// ^−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
.then(async resp =>{
const json = await resp.json()
if(json.status == "success") return json
return Promise.reject('err')
})
.catch(err => {
return Promise.reject(err)
})
}
But, three things:
There's no point whatsoever to that
catch
handler; andYou need to check for response success before calling
json
; andThere's no reason for that
then
handler to be anasync
function.
Instead:
const apiRequest = (url) => {
return fetch(url) // *** Note: Added `url` here
.then(resp => {
if (!resp.ok) {
throw new Error("HTTP status " + resp.status);
}
return resp.json();
})
};
(I've also added some missing semicolons there, but if you prefer to rely on ASI, just leave them off.)
If the fetch
promise is rejected, that rejection will be carried through to the promise from apiRequest
for the caller to handle. If the fetch
promise is fulfilled but resp.ok
is false
(because there was an HTTP level error like a 404 or 500), the promise from apiRequest
will be rejected with the error thrown in the then
handler. If those things work but the json
call fails, the promise from apiRequest
will be rejected with the error from json
. Otherwise, the promise from apiRequest
will be fulfilled with the parsed data.
It can also be a concise form arrow function if you prefer:
const apiRequest = (url) => fetch(url).then(resp => { // *** Note: Added `url` to `fetch` call
if (!resp.ok) {
throw new Error("HTTP status " + resp.status);
}
return resp.json();
});
Your original code used an async
function in then
. If you can ues async
functions in your environment, you may prefer to make apiRequest
an async
function:
const apiRequest = async (url) => {
const resp = await fetch(url); // *** Note: Added `url` here
if (!resp.ok) {
throw new Error("HTTP status " + resp.status);
}
return resp.json();
};
Related Topics
JavaScript - Convert Array of Arrays into Array of Objects with Prefilled Values
Firestore: What's the Pattern for Adding New Data in Web V9
Order of Hoisting in JavaScript
How to Make API Call with Hooks in React
How to Sort an Array of Objects Based on the Ordering of Another Array
How to Sort Numbers Correctly with Array.Sort()
JavaScript Es6 Class Definition Not Accessible in Window Global
Js Function to Calculate Complementary Colour
JavaScript Can't Find Element by Id
How to Return a JavaScript String from a Webassembly Function
Jquery .Load()/.Ajax() Not Executing JavaScript in Returned HTML After Appended
How to Convert String to Number According to Locale (Opposite of .Tolocalestring)
Returning a Value from Callback Function in Node.Js
(Deep) Copying an Array Using Jquery
Retrieving Binary File Content Using JavaScript, Base64 Encode It and Reverse-Decode It Using Python