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

Daniel Kreider
Daniel Kreider
Published on December 5th at 7:00am
  • Quick Guide
  • API

How do you gracefully retry a failed HTTP request?

Here's the few lines of Angular code you can use to manage HTTP failures.

Some Angular apps 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 more nimble and tough 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
    }
]

Wield 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 reauthentication proceedure like 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.

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 poke me.

Angular Expert & Consultant