Let’s say you want to retry error requests in Angular and aren’t sure how to do it. If you have used the retryWhen operator, which will be removed from future versions of RxJS, this article is also for you.
I will assume that you already have created a project with the ng new
command in the Angular CLI.
So, to be able to retry requests, first of all, we have to know which requests to retry and somehow catch them. To do that we will need to use an Angular Interceptor. I will create an interceptor named retry
in the core/interceptors
folder by running the following command:
ng g i core/interceptors/retry
After running the command, our folder structure should look like this:
And our retry.interceptor.ts should have the following code:
import { Injectable } from '@angular/core';
import {
HttpRequest,
HttpHandler,
HttpEvent,
HttpInterceptor,
HttpErrorResponse,
} from '@angular/common/http';
import { Observable, retry, timer } from 'rxjs';
@Injectable()
export class RetryInterceptor implements HttpInterceptor {
constructor() {}
intercept(
request: HttpRequest<unknown>,
next: HttpHandler
): Observable<HttpEvent<unknown>> {
return next.handle(request)
}
}
What do we have to do here?
So, by default we would pipe the return request and use retryWhen operator from RxJS. But, as the retryWhen is going to be deprecated as of version 9 or 10, we will use the suggested error operator from RxJS – retry. Hmm… how to use the retry to retry when an error occurs? – Easy. Watch me. 🙂
I will make a function that checks if it should retry or not, or maybe it would be better to say that I will make a function that retries requests with certain status codes.
shouldRetry(error: HttpErrorResponse){
if(error.status >= 500){
return timer(1000);
}
throw error;
}
The next step is to add the retry operator to the cought request.
intercept(request: HttpRequest<unknown>, next: HttpHandler): Observable<HttpEvent<unknown>> {
return next.handle(request).pipe(retry({count: 2, delay: this.shouldRetry}));
}
Let me explain what just happened.
As the retry operator is able to receive an object of properties, we are adding count
– that counts for how many times the request should be retried. And also, we are adding the delay
property, that fires the retry after the given period of time. But, there is a catch. The delay is expecting an observable, not just a number.
So to add it, we have used the timer
operator from RxJS. Also, as you could mention, we are retrying only server errors (status codes 5xx).
Importing interceptor into app module
To be able to use our interceptor, we have to import it into our app module somehow. So here is a piece of code that as to be in the app.module.ts
.
Ps. take a look at the providers array.
import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http';
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import { RetryInterceptor } from './core/interceptors/retry.interceptor';
@NgModule({
declarations: [AppComponent],
imports: [BrowserModule, HttpClientModule],
providers: [
{
provide: HTTP_INTERCEPTORS,
useClass: RetryInterceptor,
multi: true,
},
],
bootstrap: [AppComponent],
})
export class AppModule {}
How to test it?
To test this, you just have to make an http request to an API that returns an error with number 500 or more.
I will help you with that as well. Here is a website that is actually doing just that, returning specific status codes using an API.
https://httpstat.us – you are welcome 🙂
Conclusion
Retrying error requests using retry operator seems shorter and more readable than using retryWhen (in my opinion) and it is really easy to implement.
You can also find the full code on my github page, or on the following link: adnan-halilovic/retry-http-requests-angular: Retry Error HTTP Requests in Angular (github.com)