Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

fetch: Reject promise with JSON error object

I have an HTTP API that returns JSON data both on success and on failure.

An example failure would look like this:

~ ◆ http get http://localhost:5000/api/isbn/2266202022  HTTP/1.1 400 BAD REQUEST Content-Length: 171 Content-Type: application/json Server: TornadoServer/4.0  {     "message": "There was an issue with at least some of the supplied values.",      "payload": {         "isbn": "Could not find match for ISBN."     },      "type": "validation" } 

What I want to achieve in my JavaScript code is something like this:

fetch(url)   .then((resp) => {      if (resp.status >= 200 && resp.status < 300) {        return resp.json();      } else {        // This does not work, since the Promise returned by `json()` is never fulfilled        return Promise.reject(resp.json());      }    })    .catch((error) => {      // Do something with the error object    } 
like image 371
jbaiter Avatar asked Apr 06 '15 14:04

jbaiter


People also ask

How do you catch an error in a Promise?

catch " around the executor automatically catches the error and turns it into rejected promise. This happens not only in the executor function, but in its handlers as well. If we throw inside a . then handler, that means a rejected promise, so the control jumps to the nearest error handler.

How do I return a failed Promise?

The Promise. reject() method is used to return a rejected Promise object with a given reason for rejection. It is used for debugging purposes and selective error catching.

How do you catch an error in fetch?

The fetch() function will automatically throw an error for network errors but not for HTTP errors such as 4xx or 5xx responses. For HTTP errors we can check the response. ok property to see if the request failed and reject the promise ourselves by calling return Promise.


2 Answers

 // 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;}); 
like image 187
Bergi Avatar answered Sep 20 '22 09:09

Bergi


Here's a somewhat cleaner approach that relies on response.ok and makes use of the underlying JSON data instead of the Promise returned by .json().

function myFetchWrapper(url) {    return fetch(url).then(response => {      return response.json().then(json => {        return response.ok ? json : Promise.reject(json);      });    });  }    // This should trigger the .then() with the JSON response,  // since the response is an HTTP 200.  myFetchWrapper('http://api.openweathermap.org/data/2.5/weather?q=Brooklyn,NY').then(console.log.bind(console));    // This should trigger the .catch() with the JSON response,  // since the response is an HTTP 400.  myFetchWrapper('https://content.googleapis.com/youtube/v3/search').catch(console.warn.bind(console));
like image 29
Jeff Posnick Avatar answered Sep 19 '22 09:09

Jeff Posnick