How to retry an HTTP request in Angular (with code examples)


Want to retry a failed HTTP request?

Here's to manage HTTP failures in Angular.

Some Angular apps are slow.

And can be as clumsy as a soccer-playing elephant.

When they fail they fall HARD.

And others are as nimble as a head-bonking rock star.

Want to learn how to retry an HTTP request?

Interested in knowing how you can make your Angular web app better by gracefully handing HTTP failures?

Then you're in the right place. Here's what we're going to cover.

It starts with an HTTP interceptor

Open a terminal in your Angular project and whip it up with the Angular CLI like so.

ng generate interceptor monitor

And then we'll import it into our module file by adding it to the providers array.

providers: [
    { 
      provide: HTTP_INTERCEPTORS, 
      useClass: MonitorInterceptor, 
      multi: true
    }
]

If you're project is using the new app.config.ts file instead of Angular modules then we'll provide our HTTP client along with the interceptor like this.

import { ApplicationConfig } from '@angular/core';
import { provideHttpClient, withInterceptors } from '@angular/common/http';
import { monitorInterceptor } from './monitor.interceptor';

export const appConfig: ApplicationConfig = {
    providers: [
        provideHttpClient(
            withInterceptors([monitorInterceptor])
        )
    ],
};

Use the interceptor to retry failed HTTP requests

Next we'll open the new monitor.interceptor.ts file. It should look something like this.

import { Injectable } from '@angular/core';
import {
  HttpRequest,
  HttpHandler,
  HttpEvent,
  HttpInterceptor
} from '@angular/common/http';
import { Observable } from 'rxjs';

@Injectable()
export class MonitorInterceptor implements HttpInterceptor {

  constructor() {}

  intercept(request: HttpRequest<unknown>, next: HttpHandler): Observable<HttpEvent<unknown>> {
    return next.handle(request);
  }
}

As you probably already know this interceptor can be used to modify any incoming or outgoing HTTP requests.

How do we get the benefits of an Angular interceptor and use it to retry any failed HTTP request? The answer is simple.

To add the retry capability we'll use the retry function that triggers a retry when the Observable fails.

Here's how you do it, buster.

import { Injectable } from '@angular/core';
import {
  HttpRequest,
  HttpHandler,
  HttpEvent,
  HttpInterceptor
} from '@angular/common/http';
import { Observable } from 'rxjs';
import { retry } from 'rxjs/operators';

export const retryCount = 3;

@Injectable()
export class MonitorInterceptor implements HttpInterceptor {

  constructor() {}

  intercept(request: HttpRequest<unknown>, next: HttpHandler): Observable<HttpEvent<unknown>> {
    return next.handle(request).pipe(
      retry(retryCount)
    )
  }
}

Now if any HTTP request fails it will retry that request another 3 times.

How do you retry on certain response status codes?

import { Injectable } from '@angular/core';
import {
  HttpRequest,
  HttpHandler,
  HttpEvent,
  HttpInterceptor
} from '@angular/common/http';
import { Observable, of, throwError } from 'rxjs';
import { concatMap, delay, retryWhen } from 'rxjs/operators';

export const retryCount = 3;
export const retryWaitMilliSeconds = 1000;

@Injectable()
export class MonitorInterceptor implements HttpInterceptor {

  constructor() {}

  intercept(request: HttpRequest<unknown>, next: HttpHandler): Observable<HttpEvent<unknown>> {
    return next.handle(request).pipe(
      retryWhen(error => 
        error.pipe(
          concatMap((error, count) => {
            if (count <= retryCount && error.status == 503) {
              return of(error);
            }
            return throwError(error);
          }),
          delay(retryWaitMilliSeconds)
        )
      )
    )
  }
}

How do you resend request after a token refresh?

How do a handle a scenario when the server responds with a 401? And you need to do some sort of login or token refresh?

Here's the code.

import { Injectable } from '@angular/core';
import {
  HttpRequest,
  HttpHandler,
  HttpEvent,
  HttpInterceptor
} from '@angular/common/http';
import { Observable, throwError } from 'rxjs';
import { catchError, switchMap } from 'rxjs/operators';

export const retryCount = 3;

@Injectable()
export class MonitorInterceptor implements HttpInterceptor {

  constructor() {}

  intercept(request: HttpRequest<unknown>, next: HttpHandler): Observable<HttpEvent<unknown>> {
    return next.handle(request).pipe(catchError(error => {
        if (error.status === 401) {
          return this.reAuthenticate().pipe(
            switchMap(() => next.handle(request))
          )
        }
        return throwError(error);
      })
    )
  }

  reAuthenticate(): Observable<any> {
    // Do your auth call here
  }
}

And in case you need it, you can find a more elaborate example here.

Conclusion

In this guide we've looked at different ways to gracefully handle a failed HTTP request with the Angular HTTP client.

Failing gracefully might seem like a small detail that's not worth batting an eye-lid at but when done properly your users will be appreciative.

Questions or comments? Please don't hesitate to reach out.

Angular Developer & Consultant