How to execute an async fetch request and then retry last failed request? : <p><a href="https://github.com/apollographql/apollo-link/tree/master/packages/apollo-link-error#retrying-failed-requests" rel="noreferrer">Apollo link offers an error handler <code>onError</code></a></p>

<p><strong>Issue:</strong>
Currently, we wish to refresh oauth tokens when they expires during an apollo call and we are unable to execute an async fetch request inside the <code>onError</code> properly. </p>

<p><strong>Code:</strong></p>

<p><code>initApolloClient.js</code>
</p>

<pre><code>import { ApolloClient } from 'apollo-client';
import { onError } from 'apollo-link-error';
import { ApolloLink, fromPromise } from 'apollo-link';

//Define Http link
const httpLink = new createHttpLink({
    uri: '/my-graphql-endpoint',
    credentials: 'include'
});

//Add on error handler for apollo link

return new ApolloClient({
    link: ApolloLink.from([
        onError(({ graphQLErrors, networkError, operation, forward  }) =&gt; {
            if (graphQLErrors) {
                //User access token has expired
                if(graphQLErrors[0].message==="Unauthorized") {
                    //We assume we have both tokens needed to run the async request
                    if(refreshToken &amp;&amp; clientToken) {
                        //let's refresh token through async request
                        return fromPromise(
                            authAPI.requestRefreshToken(refreshToken,clientToken)
                            .then((refreshResponse) =&gt; {
                                let headers = {
                                    //readd old headers
                                    ...operation.getContext().headers,
                                    //switch out old access token for new one
                                    authorization: `Bearer ${refreshResponse.access_token}`,
                                };

                                operation.setContext({
                                    headers
                                });

                                //Retry last failed request
                                return forward(operation);
                            })
                            .catch(function (error) {
                                //No refresh or client token available, we force user to login
                                return error;
                            })
                        )
                    }
                }
            }
        }
    }
}),
</code></pre>

<p>What happens is:</p>

<ol>
<li>Initial graphQL query runs and fails due to unauthorization</li>
<li>The <code>onError</code> function of <code>ApolloLink</code> is executed.</li>
<li>The promise to refresh the token is executed.</li>
<li>The <code>onError</code> function of <code>ApolloLink</code> is executed again??</li>
<li>The promise to refresh the token is completed.</li>
<li>The initial graphQL query result is returned and its data is <code>undefined</code></li>
</ol>

<p>Between step 5 and 6, <em>apollo doesn't re-run the initial failed graphQL query</em> and hence the result is <code>undefined</code>.</p>

<p><strong>Errors from console:</strong></p>

<pre class="lang-js prettyprint-override"><code>Uncaught (in promise) Error: Network error: Error writing result to store for query:
 query UserProfile($id: ID!) {
  UserProfile(id: $id) {
    id
    email
    first_name
    last_name
    }
    __typename
  }
}
</code></pre>

<p>The solution should allow us to:</p>

<ol>
<li>Run an async request when an operation fails</li>
<li>Wait for the result of the request</li>
<li>Retry failed operation with data from the request's result</li>
<li>Operation should succeed to return its intended result</li>
</ol>
