DEV Community

Cover image for How to retry an HTTP request in Angular (with plenty of code examples)
Daniel Kreider
Daniel Kreider

Posted on • Originally published at danielk.tech

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

How do you gracefully deal with 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.

Alt Text

Interested in knowing how you can make your Angular web app more nimble and tough by gracefully handing HTTP failures? Read on.

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
Enter fullscreen mode Exit fullscreen mode

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
    }
]
Enter fullscreen mode Exit fullscreen mode

Wield the interceptor to retry failed 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);
  }
}
Enter fullscreen mode Exit fullscreen mode

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? 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)
    )
  }
}
Enter fullscreen mode Exit fullscreen mode

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)
        )
      )
    )
  }
}
Enter fullscreen mode Exit fullscreen mode

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
  }
}
Enter fullscreen mode Exit fullscreen mode

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.

Top comments (0)