How to add a retry mechanism to api calls with Axios

How to add a retry mechanism to api calls with Axios

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.
 
  1. We can use interceptors which can intercept requests and responses before they are handled by then or catch.
  1. 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.
 
 
notion image
 
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:
  1. Request aborted
  1. Network error
  1. Network timeout
  1. 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.
 
notion image
 
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 ♥️.