Intro
Recently at work I had to implement a retry mechanism to an api call. The problem was when the user visits the web app for the first time an api call that displays data on the page would fail on the first try but would work on api calls after the first one, so the solution was to implement some sort of retry mechanism so that the call is tried 3 times or 5 times before we actually throw an error.
Other cases could be, for example when the user accesses our web app, the HTTP request may fail due to unstable networks, such as timeout or network exception. In this case, there will usually be an exception page to inform the user that they can re-enter the web app later. If we retry these failed HTTP requests, the user may not need to exit and re-enter our web app, the experience will be better.
We will look at two ways to solve this problem.
- We can use interceptors which can intercept requests and responses before they are handled by
then
orcatch
.
- We will look at axios-retry which is a Axios plugin that intercepts failed requests and retries them whenever possible.
1st Approach.
We will first look at some of the exceptions that may occur if Axios requests fail, then use the interceptor of Axios to retry the HTTP request.
If you have observed the exception of Axios, you can find that the name of all exceptions is
AxiosError
. Axios custom handling exception AxiosError
class which inherit from Error
. We can find all exceptions by searching the source code for AxiosError.You will notice about 20 places where it is used, but we only need to pay attention to the exceptions during the request.
The main exceptions are:
- Request aborted
- Network error
- Network timeout
- Unsupported protocol
The exception of
Request aborted
maybe caused by the user canceling the request, we might not retry the request. And the exception of Unsupported protocol
doesn’t need to retry as it will fail again. So we can retry the request while the request has failed for Network error
or Network timeout
.While using Axios, we can use interceptors which can intercept requests and responses before they are handled by
then
or catch
. The interceptor accepts two parameters, fulfilled callback
and rejected callback
. When a request fails, it will execute the rejected callback.axios.interceptors.response.use(undefined, (err) => { const { config, message } = err; if (!config || !config.retry) { return Promise.reject(err); } // retry while Network timeout or Network Error if (!(message.includes("timeout") || message.includes("Network Error"))) { return Promise.reject(err); } config.retry -= 1; const delayRetryRequest = new Promise((resolve) => { setTimeout(() => { console.log("retry the request", config.url); resolve(); }, config.retryDelay || 1000); }); return delayRetryRequest.then(() => axios(config)); }); // when request, can set retry times and retry delay time axios.get(url, {retry: 3, retryDelay: 3000});
In typescript you would implement it like this
import 'axios'; declare module 'axios' { export interface AxiosRequestConfig { retry?: boolean; retryDelay?: boolean; } } axios.interceptors.response.use(undefined, (err) => { const { config, message } = err; if (!config || !config.retry) { return Promise.reject(err); } // retry while Network timeout or Network Error if (!(message.includes("timeout") || message.includes("Network Error"))) { return Promise.reject(err); } config.retry -= 1; const delayRetryRequest = new Promise((resolve) => { setTimeout(() => { console.log("retry the request", config.url); resolve(); }, config.retryDelay || 1000); }); return delayRetryRequest.then(() => axios(config)); }); // when request, can set retry times and retry delay time axios.get(url, {retry: 3, retryDelay: 3000});
for testing the feature, we can block the request URL with Devtools.
By using the interceptor of Axios to intercept the response, if a
Network timeout
or Network error
occurs, try to send the request again. We can control the number of retrying requests and the interval between each request by setting retry
and retryDelay
.2nd Approach
We can make use of the axios-retry which is a Axios plugin that intercepts failed requests and retries them whenever possible. Using this will also reduce the lines of code you have to write to implement this retry mechanism.
First install this using NPM or Yarn.
npm install axios-retry
We can use it like this and axios-retry gives a few options as well
// CommonJS // const axiosRetry = require('axios-retry'); // ES6 import axiosRetry from 'axios-retry'; axiosRetry(axios, { retries: 3 }); axios.get('http://example.com/test') // The first request fails and the second returns 'ok' .then(result => { result.data; // 'ok' }); ------------------------------------------------ // Exponential back-off retry delay between requests axiosRetry(axios, { retryDelay: axiosRetry.exponentialDelay }); ------------------------------------------------ // Custom retry delay axiosRetry(axios, { retryDelay: (retryCount) => { return retryCount * 1000; }}); ------------------------------------------------ // Works with custom axios instances const client = axios.create({ baseURL: 'http://example.com' }); axiosRetry(client, { retries: 3 }); client.get('/test') // The first request fails and the second returns 'ok' .then(result => { result.data; // 'ok' }); ------------------------------------------------ // Allows request-specific configuration client .get('/test', { 'axios-retry': { retries: 0 } }) .catch(error => { // The first request fails error !== undefined });
Thats it for today folks, Have a great day ♥️.