nestjs / axios

Axios module for Nest framework (node.js) 🗂

Home Page:https://docs.nestjs.com/techniques/http-module

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Сonfigurable axios instance with retrays and interceptors.

Weplik opened this issue · comments

Is there an existing issue that is already proposing this?

  • I have searched the existing issues

Is your feature request related to a problem? Please describe it

Hi!

When using the package, I constantly encounter problems:

  1. There is no possibility to set a retry. To do this, you need to do some utility functions in the services, or connect third-party libraries. Since you can not trust third-party services and it is better to do a retry if the request is unsuccessful (For example, status 503).
  2. There is no possibility to additionally configure axios instance. For example, I almost always need to specify an interceptor that would transform the error by deleting sensitive data (for example, auth token).

Therefore, I constantly need to do some actions when using methods from HTTPService.

Describe the solution you'd like

I would like to be able to pass options for the retry and interceptors at once when initializing HttpModule.

Example with retries:

export type RetryOptions = {
    retryableStatuses: number[]; // statuses under which the retry will be made
    retryableCodes: string[]; // codes under which the retry will be made
    limit: number; // limit of retries
    delay: number; // delay for retry
}

export type HttpModuleOptions = {
    axiosConfig: AxiosRequestConfig;
    retryOptions?: RetryOptions;
};


export class HttpService {
    constructor(@Inject(RETRY_OPTIONS) private readonly retryOptions: RetryOptions | undefined) {}

    request<T = any>(config: AxiosRequestConfig): Observable<AxiosResponse<T>> {
        const obs = this.makeObservable<T>(this.instance.request, config);

        return this.makeRetryableRequest(obs);
    }

    protected makeRetryableRequest<TResponseData = unknown>(
        response: Observable<AxiosResponse<TResponseData>>
    ): Observable<AxiosResponse<TResponseData>> {
        if (this.retryOptions === undefined) {
            return response;
        }

        return response.pipe(rxjs.retry({ delay: ..., count: ... })).
    }
}

Example with interceptors:

export type Interceptor = {
    onFulfilled: (value: any) => any;
    onRejected: (error: any) => any;
    options?: AxiosInterceptorOptions;
}

export type HttpModuleOptions = {
    axiosConfig: AxiosRequestConfig;
    axiosInstanceInterceptors?: { response: Interceptor[] };
};

export class HttpService {
    constructor(
        @Inject(AXIOS_INSTANCE_TOKEN)
        protected readonly instance: AxiosInstance = Axios,
        @Inject(AXIOS_INSTANCE_INTERCEPTORS)
        private readonly interceptors: Interceptor[],
    ) {
        this.interceptors.forEach(interceptor => {
            instance.response.use(interceptor.onFulfilled, interceptor.onRejected, interceptor.options);
        });
    }
}

Teachability, documentation, adoption, migration strategy

No response

What is the motivation / use case for changing the behavior?

When initializing the module, I want to immediately set everything that is necessary to work with axios :)

I specified the use cases in the problems.

Thanks for your suggestion!

This has been discussed in the past and we decided to not implement it in the foreseeable future.

If you think your request could live outside Nest's scope, we'd encourage you to collaborate with the community on publishing it as an open source package.