Exponential backoff is a technique used in API communication to handle situations when the server is temporarily overloaded or unavailable.

Instead of making repeated requests to the server immediately, the client waits for an increasing amount of time before trying again.
Here’s an example of how you can implement exponential backoff in Typescript:
import axios, { AxiosRequestConfig } from 'axios';
type APICallParams = Readonly<{
url: string;
payload?: Record<string, unknown>;
}>;
type APICallResponseData = Readonly<{
id: number;
title: string;
description: string;
price: number;
discountPercentage: number;
rating: number;
stock: number;
brand: string;
category: string;
thumbnail: string;
images: string[];
}>;
const MAX_RETRIES = 3;
const BASE_DELAY_IN_MS = 1000;
const expBackoffAPICall = async (
payload: APICallParams
): Promise<APICallResponseData | null> => {
let retries = 0;
let delay = BASE_DELAY_IN_MS;
while (retries < MAX_RETRIES) {
try {
const options: Readonly<AxiosRequestConfig> = {
data: payload || null,
};
const response = await axios.get(payload.url, options);
return response.data;
} catch (error) {
console.error(`Error calling API: ${(error as Error).message}`);
retries++;
if (retries < MAX_RETRIES) {
// Calculate the delay time using exponential backoff
delay = BASE_DELAY_IN_MS * Math.pow(2, retries);
console.log(`Retrying after ${delay} ms`);
await new Promise((resolve) => setTimeout(resolve, delay));
} else {
console.error(`Max retries reached, giving up.`);
throw error;
}
}
}
return null;
};
// Call the API with exponential backoff
expBackoffAPICall({
url: 'https://dummyjson.com/products/1',
})
.then((responseData) => console.log(`API response data: ${responseData}`))
.catch((error) => console.error(`API Call Failed: ${error.message}`));
Explanation
Here’s a step-by-step explanation of each part of the code:
import axios, { AxiosRequestConfig } from 'axios';
Here, you are importing Axios (the library being used for a fetch request. Alternatively, you can also use the HTTP module for API calls.
type APICallParams = Readonly<{
url: string;
payload?: Record<string, unknown>;
}>;
type APICallResponseData = Readonly<{
id: number;
title: string;
description: string;
price: number;
discountPercentage: number;
rating: number;
stock: number;
brand: string;
category: string;
thumbnail: string;
images: string[];
}>;
After the import
statements, we are defining types for our expBackoffAPICall
function. I’m hoping that the names are self-evident, but for those not familiar with Typescript here’s some info.
The type APICallParams
is the type defined for the function expBackoffAPICall
. This is the function that we’ll use to pass the API URL and payload.
The type APICallResponseData
is the type defined for the shape of the API call response. You’ll need to modify this type based on the response object that your own API call returns.
You can use a tool like https://app.quicktype.io for making types from your API response JSON.
const MAX_RETRIES = 3;
const BASE_DELAY = 1000;
These two constants define the maximum number of retries and the base delay time, respectively. In this case, we set the maximum number of retries to 3
, and the base delay time to 1000
milliseconds (or 1 second).
const expBackoffAPICall = async (
payload: APICallParams
): Promise<APICallResponseData | null> => {
let retries = 0;
let delay = BASE_DELAY_IN_MS;
while (retries < MAX_RETRIES) {
try {
const options: Readonly<AxiosRequestConfig> = {
data: payload || null,
};
const response = await axios.get(payload.url, options);
return response.data;
} catch (error) {
console.error(`Error calling API: ${(error as Error).message}`);
retries++;
if (retries < MAX_RETRIES) {
// Calculate the delay time using exponential backoff
delay = BASE_DELAY_IN_MS * Math.pow(2, retries);
console.log(`Retrying after ${delay} ms`);
await new Promise((resolve) => setTimeout(resolve, delay));
} else {
console.error(`Max retries reached, giving up.`);
throw error;
}
}
}
return null;
};
This is the function body that actually calls the API and retries the API call in case of an error.
This function expBackoffAPICall
is where we implement the exponential backoff strategy. Inside this function, we initialize two variables: retries
to keep track of the number of attempts, and delay
to store the delay time before the next retry.
We then start a while
loop that runs until either the maximum number of retries is reached, or a successful response is received. Inside the loop, we try to make the API request using axios.get
and return the response data if the request is successful.
If the request fails due to an error, we log the error message and increment the retries
counter. If the maximum number of retries has not been reached yet, we calculate the next delay time using exponential backoff. We do this by multiplying the BASE_DELAY
by 2
raised to the power of retries
.
We then log a message indicating that we’re going to retry after the calculated delay time and use setTimeout
to pause the execution for the calculated delay time before trying the API request again.
If the maximum number of retries has been reached, we log an error
message and throw the original error.
The last part of the code is as follows:
// Call the API with exponential backoff
expBackoffAPICall({
url: 'https://dummyjson.com/products/1',
})
.then((responseData) => console.log(`API response data: ${responseData}`))
.catch((error) => console.error(`API Call Failed: ${error.message}`));
Here, we call the expBackoffAPICall
function and handle the response and error accordingly. In this example, we log the API response if the request is successful, or the error message if it fails after the maximum number of retries.
Leave a Reply