Fetch: Reject Promise with JSON Error Object

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:

  1. There's no point whatsoever to that catch handler; and

  2. You need to check for response success before calling json; and

  3. There's no reason for that then handler to be an async 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



Leave a reply



Submit