0

I've written the code below in an attempt to gracefully handle both connection errors and non-OK HTTP status codes, as well as retrying in some cases.

For some reason, that I can't deduce by reading the code, in case of a bad HTTP status code, a Promise is passed as argument to the function given to catch (I know ’catch()` itself returns a Promise). Ie.

testGet(500).catch(res => console.log(res))

will print [object Promise]

Can anyone tell me where I throw a Promise object in the code below? Or, in other words, why handleStatusError returns a Promise, when it appears to be given a Response (which it returns)?

// **** Behavior ****
// 
// HTTP error 4xx:   Don't retry (we messed up)
// HTTP error 5xx:   Retry (the server messed up)
// Connection error: Retry (ITU's wifi messed up)

export function testGet(code) {
    var url = "http://httpstat.us/" + code
    console.log("Fetching '" + url + "'")
    return httpGet(url, 2);
}

export function httpGet(url, numRetries) { 
    var options = { 
        mode: 'cors',
        headers: {
            'Accept':       'application/json',
          }
    };
    return fetchRetry(url, options, numRetries);
}

export function httpPost(url, body, numRetries) { 
    var options = {
        method: 'POST',
        headers: {
          'Accept':       'application/json',
          'Content-Type': 'application/json',
        },
        body: JSON.stringify(body),
    };
    return fetchRetry(url, options, numRetries); 
}

function fetchRetry(url, options, numRetries) {
    numRetries = numRetries || 1;
    return httpRequest(url, options).catch(error => {
        if (numRetries <= 1 || error.retry !== true) {
            throw error.json();
        } else {
            return fetchRetry(url, options, numRetries - 1);
        }
    });
}

function httpRequest(url, options) {
    return fetch(url, options)
        // Handle connection/network error
        .catch(error => { 
            error.retry = true;
            error.json = () => error.message || "Network/connection error";
            throw error;
        })
        .then(response => { 
            if (response.ok) return response.json();
            // Handle HTTP status code error
            else throw handleStatusError(response);
        });
}

const handleStatusError = response => {
    response.retry = false;
    // Check status code
    var status = response.status;
    if (status >= 400 && status < 500) {        // User error
        response.retry = false;
    } else if (status >= 500 && status < 600) { // Server error
        response.retry = true;
    }
    return response;
}
runeks
  • 1,745
  • 2
  • 17
  • 26
  • 2
    `throw error.json();` .json() returns a promise. [see here](https://developer.mozilla.org/en-US/docs/Web/API/Body/json) -- actually, you overwrite that. but handleStatusError _does_ appear to return a promise. – rlemon Jun 04 '18 at 16:06
  • @rlemon Yes, handleStatusError returns a Promise, but why does it do that? It returns the argument it gets from the function passed to “then”, which should be a Response as far as I can see. – runeks Jun 05 '18 at 17:15
  • @rlemon Actually, I think you answered my question. I didn’t know .json() returned a Promise. .json() is not overwritten in case a status error is encountered — only if it’s a connection error. – runeks Jun 05 '18 at 17:29

0 Answers0