2

I want my fetch request to have some sort of retry system if it somehows fails based on the HTTP code of the response (for example: not 200). It looks something like this:

fetch('someURLWithAJSONfile/file.json')
        .then(function (res) {
            console.log(res.status);
            if (res.status !== 200) {
                console.log("There was an error processing your fetch request. We are trying again.");

// Recursive call to same fetch request until succeeds

            } else {
                return res.json();
            }
        }).then(function (json) {
        data = json;
    }).catch(function (err) {
        console.log(`There was a problem with the fetch operation: ${err.message}`);
    });

Is there a way to put the fetch request inside a custom Promise and make it call itself after checking its http response status?

danielsto
  • 134
  • 5
  • 17
  • Sure there is. It's just a promise, and those can be chained and nested. Please show us the code of your attempt. – Bergi Sep 25 '17 at 15:37
  • The `data = json;` is [what won't work](https://stackoverflow.com/q/23667086/1048572) – Bergi Sep 25 '17 at 15:38

2 Answers2

5

Here the simple ES6 solution (since you are using fetch). The limit option means how many times you want to try your request.

var doRecursiveRequest = (url, limit = Number.MAX_VALUE) => 
  fetch(url).then(res => {
    if (res.status !== 200 && --limit) {
      return doRecursiveRequest(url, limit);
    } 
    return res.json();
  });

doRecursiveRequest('someURLWithAJSONfile/file.json', 10)
  .then(data => console.log(data))
  .catch(error => console.log(error));
dhilt
  • 18,707
  • 8
  • 70
  • 85
  • This solution always returns error undefined in the '.then' call (regardless of the res.status). The other solution below with the traditional function (not carrot) works without error. – stereopan-com Sep 07 '20 at 23:40
  • This solution well works with react native under `useEffect`. – Baris Senyerli Apr 21 '22 at 21:36
4

You can do this by wrapping your call to fetch in a named function that returns the promise created by fetch. Consider:

function fetchWithRetry(url, retryLimit, retryCount) {
    retryLimit = retryLimit || Number.MAX_VALUE;
    retryCount = Math.max(retryCount || 0, 0);
    return fetch(url).then(function (res) {
        console.log(res.status);
        if (res.status !== 200 && retryCount < retryLimit) {
            console.log("There was an error processing your fetch request. We are trying again.");
            return fetchWithRetry(url, retryLimit, retryCount + 1);
        } else {
            return res.json();
        }
    });
}

fetchWithRetry('someURLWithAJSONfile/file.json', 10).then(function (json) {
    data = json;
}).catch(function (err) {
    console.log(`There was a problem with the fetch operation: ${err.message}`);
});

This code wraps your existing call and takes advantage of closure scope to maintain a retry limit and count which are both optional. You then call the fetchWithRetry function with a URL just like you did your previous call to fetch. If you do not pass a retry limit it will continue endlessly. The final retryCount variable is really only used for recursion purposes and is meant to be called internally.

musicfuel
  • 1,532
  • 10
  • 7