Implementing Retry Functionality with Axios in NestJS

I am integrating a third-party API into my NestJS application to retrieve data and perform certain operations. Occasionally, the API throws a 400 Bad Request error, in which case I need to retry the call after a waiting period of 1 second. What is the best and most efficient way to handle this scenario?

service.ts

async fetchData() {
  try {
    const response = await axios.get('my-api-irl')
    // .. performing some data manipulation with the response
  } catch (error) {
    // Need to implement retry logic for error status code 400
  }
}

Answer №1

Suppose you need to handle retrying an Axios call in your NestJS application upon encountering a 400 Bad Request error. You can make use of the nestjs-axios-retry package that has been developed specifically for this purpose. This package offers a seamless and effective approach to incorporating retry logic into your HTTP requests. Here's how you can implement it in your particular situation:

  1. Start by installing the nestjs-axios-retry and axios-retry packages:
npm install nestjs-axios-retry axios-retry
  1. Next, configure the AxiosRetryModule within your NestJS module - within your AppModule (or any applicable module), import and set up the AxiosRetryModule as shown below:

import { Module } from '@nestjs/common';
import { AxiosRetryModule } from 'nestjs-axios-retry';
import axiosRetry from 'axios-retry';

@Module({
  imports: [
    AxiosRetryModule.forRoot({
      axiosRetryConfig: {
        retries: 3, // Number of retry attempts
        retryDelay: (retryCount) => 1000, // Fixed 1 second delay between retries
        retryCondition: (error) => error.response.status === 400, // Retry only on 400 Bad Request
      },
    }),
  ],
  // ... Other configurations
})
export class AppModule {}

  1. Utilize the HttpService in your service - inject the HttpService offered by NestJS into your service. The retry functionality will now be automatically applied based on your module configuration:

import { Injectable } from '@nestjs/common';
import { HttpService } from '@nestjs/axios';
import { firstValueFrom } from 'rxjs';

@Injectable()
export class AppService {
  constructor(private httpService: HttpService) {}

  async fetchData() {
    try {
      const response = await firstValueFrom(
        this.httpService.get('your-api-url'),
      );
      // ... do something with the response
      return response.data;
    } catch (error) {
      // Handle the case where all retries fail
      throw error;
    }
  }
}

async fetchDataWithExponentialBackoff() {
  const response = await firstValueFrom(
    this.httpService.get('https://example.com/data', {
      'axios-retry': {
        retries: 3,
        retryDelay: axiosRetry.exponentialDelay,
      },
    }),
  );
  return response.data;
}

async fetchDataWithOnRetryCallback() {
  const response = await firstValueFrom(
    this.httpService.get('https://example.com/data', {
      'axios-retry': {
        retries: 3,
        onRetry: (retryCount, error, requestConfig) => {
          console.log(`Retrying request attempt ${retryCount}`);
        },
      },
    }),
  );
  return response.data;
}

// Additional fetch data methods...

Answer №2

If you're looking for a solution that handles retry logic, I recommend checking out the library I recently published. Specifically, if you only want to retry on a 400 error, you can achieve it by implementing the following code snippet:

import withRetry from "@teneff/with-retry/decorator";
import axios, { AxiosError } from "axios";

class ErrorOnWhichWeShouldRetry extends Error {
  constructor(readonly cause?: Error) {
    super();
  }
}

export class Something {
  @withRetry({
    errors: [ErrorOnWhichWeShouldRetry],
    maxCalls: 5,
    delay: 1000,
  })
  async fetchData() {
    try {
      const response = await axios.get("my-api-irl");
      return handleResponse(response);
    } catch (err) {
      if (isAxiosError(err) && err.code === '400') {
        throw new ErrorOnWhichWeShouldRetry(err);
      }
      throw err
    }
  }
}

const isAxiosError = (err: unknown): err is AxiosError => {
  return err instanceof Error && "code" in err;
};

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Steps for connecting an external .otf file in p5.js

I'm struggling to connect a custom font file to my p5.js sketch through a URL in order to upload it on codepen.io. Unfortunately, the font is not available on Google Fonts. I attempted to include the URL in the load font function like this: loadFon ...

Subsequent $http requests become trapped in a pending state and eventually fail with a NodeJS server

I encountered a strange issue with Angular and Node that I can't seem to find a solution for. In my Angular controller, I have a function that fetches data initially and stores it in $scope. This function also allows the controller to make a POST req ...

Automatically install the development version of NW.js when running 'npm i'

Is it possible to automate the installation of the developer version of NWJS from package.json, similar to when I run npm install? For example, if I type npm i nw --nwjs_build_type=sdk I attempted to set an environment variable in my package.json like th ...

Is there a way to link a Twitter handle with Angular UI Router?

Can anyone help me with finding the correct regex to match a path like '/@someusername' with angular ui router? I've been struggling to figure it out. Currently, my routes look like this $stateProvider .state('home', {url:'/ ...

Swapping out an entire chunk of information in a JSON document

Currently, I am seeking a solution to update specific data in a JSON file without altering any other sections within it: { "task": [ { "id": 5, "title": "dave", "description": "test" }, { "id": 6, "title": "fdds ...

Creating getter and setter functions for an input field model property in Angular

I need help creating getter and setter methods for an input field property. Here is my attempted code: import { Component } from '@angular/core'; @Component({ selector: 'my-app', templateUrl: './app.component.html', st ...

Developing advanced generic functions in Typescript

I am currently working on a Hash Table implementation in Typescript with two separate functions, one to retrieve all keys and another to retrieve all values. Here is the code snippet I have so far: public values() { let values = new Array<T>() ...

How to convert a JSON response into a select box using VueJS?

I have a VueJS component where I need to populate a html select box with data from a JSON response. This is my VueJS method: getTaskList() { axios.get('/api/v1/tasklist').then(response => { this.taskList = this.data.taskList; ...

How can I verify if a date is after the current date using Node.js?

I am struggling to set up date validation that ensures the date is after the current date. This is what I have attempted so far: Router.post('/home', [ check('due_date') .isDate() .isAfter(new Date.now()) .wi ...

Modifying dynamic input fields based on the selected input field type

Seeking advice on a challenge I'm facing while testing a website. My task is to mask input fields in screenshots after executing tests because we share data with other teams. I've tried using JS before the script by changing the input type to &ap ...

List items are loaded dynamically in an unordered fashion

I have been working on a jquery slider using flickerplate. Below is the code that works when the values are hardcoded: <div class="flicker-example"> <ul> <li data-background="lib/flicker-1.jpg"> <div class ...

When attempting to upgrade from Angular 10 to 13, users may encounter the following error message: "TS2307: Unable to locate module 'path_to_service' or its corresponding type declarations."

I initially developed my Angular App using the paper-dashboard template with Angular version 10.0. Recently, I upgraded to Angular version 13 and switched to a different template - WrapPixel. However, I encountered an error when trying to include a servi ...

Use the 'url' parameter to pass into the ajax function when using jQuery for online requests

I am working with an ajax code that retrieves data from an XML file locally. <script> function myFunction() { $("#dvContent").append("<ul></ul>"); $.ajax({ type: "GET", url: "test.xml", ...

Personalize the "set up notification" PWA on React

Is it possible to customize this default design, including the picture, title, description, and background? I made changes in manifest.json, but nothing seems to have happened. Here is a picture of the random install prompt that I would like to customize ...

Using TypeScript for event handling in JointJS

I am facing a challenge in adding an event handler for jointjs paper using TypeScript. I have been unable to find a way to implement it with the joint.js definition file. private paper = new joint.dia.Paper({ el: $('#paper'), ...

Using Node.js to execute JavaScript with imported modules via the command line

Having limited experience with running JavaScript from the command line, I am facing a situation where I need to utilize an NPM package for controlling a Panasonic AC unit, which includes a wrapper for their unofficial API. My objective is to create a sim ...

Is the V8 engine programmed to populate the call stack before executing the code, or does it execute the code upon entering a function?

Below is the code I attempted: // **Setting up variables and functions** let number_object = { num: 0 } function doWork(callback) { //Initiates work, expected to complete after 5 seconds console.log("working") setTimeout(() => { ...

Implementing Do Not Track in an express application

I am trying to implement a feature named "consent" in my Nodejs express app that utilizes the Do Not Track (DNT) functionality from browsers. This function is supposed to integrate Google analytics on rendered pages only when DNT is not active or its state ...

Saving a JSON object to multiple JSON objects in TypeScript - The ultimate guide

Currently, I am receiving a JSON object named formDoc containing data from the backend. { "components": [ { "label": "Textfield1", "type": "textfield", "key": "textfield1", ...

Conceal the lower border of a targeted Tab using HTML

I'm working on a horizontal HTML tab and I want to hide the bottom border of the selected tab. Here is the code I currently have - https://jsfiddle.net/vgx2k7p5/ This issue has been raised in discussions on Stack Overflow here and here However, the ...