Axios interceptor

Let's create an axios instance that retries the network call upon failure.

Import the package and create an axios instance.

const axios = require("axios");
const instance = axios.create();

Let's add functions that execute during lifecycle of network call. .use takes two functions as argument. First function is executed on success, and second one is error handler.

instance.interceptors.request.use(
    function (config) {
        config.metadata = { startTime: new Date() };
        return config;
    },
    function (error) {
        return Promise.reject(error);
    }
);
instance.interceptors.response.use(
    function (response) {
        response.config.metadata.endTime = new Date();
        response.duration =
            response.config.metadata.endTime -
            response.config.metadata.startTime;
        return response;
    },
    function (error) {
        try {
            const { config } = error;
            // if config or retry option is not available, then return the error object 
            if (!config || !config.retry) return Promise.reject(error);

            // Set the variable for keeping track of the retry count
            config._retryCount = config._retryCount || 0;

            // Check if we've maxed out the total number of retries
            if (config._retryCount >= config.retry) {
                // Reject with the error
                return Promise.reject(error);
            }

            // Increase the retry count
            config._retryCount += 1;

            const timeOutError = error.code === "ECONNABORTED";
            const notFoundError = error.code === "ENOTFOUND";
            const connectionResetError = error.code === "ECONNRESET";

            const { status = "" } = error.response || {};
            const statusString = status.toString();
            const error_4xx = statusString.startsWith("4");
            const error_5xx = statusString.startsWith("5");

            const should_retry =
                timeOutError ||
                notFoundError ||
                connectionResetError ||
                error_4xx ||
                error_5xx;

            console.log(`[error.code]`, error.code);
            console.log(`[error_4xx]`, error_4xx);
            console.log(`[error_5xx]`, error_5xx);
            console.log(`[should_retry]`, should_retry);

            if (should_retry) {
                // Create new promise to handle exponential backoff
                const backoff = new Promise(function (resolve) {
                    setTimeout(function () {
                        resolve();
                    }, config.retryDelay || 1);
                });

                return backoff.then(() => {
                    return instance(config);
                });
            } 
            error.config.metadata.endTime = new Date();
            error.duration =
                error.config.metadata.endTime - error.config.metadata.startTime;
            return Promise.reject(error);
        } catch (err) {
            console.log(`got error in try-catch`, err);
            error.config.metadata.endTime = new Date();
            error.duration =
                error.config.metadata.endTime - error.config.metadata.startTime;
            return Promise.reject(error);
        }
    }
);

Now export this instance from as a module and use it for network request.

instance({
    method: "GET",
    url,
    timeout: 30000,
    retry: 3,
    retryDelay: 1000,
})
    .then((response) => {
        // console.log(`[response]`, response);
        const { data, status, statusText } = response;
        console.log(`status`, status);
        console.log(`data`, data);
    })
    .catch((err) => {
        const { status, statusText } = err.response || {};
        console.log(`[error status]`, status, statusText);
        // console.error(err);
    });