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.
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
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 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? 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
}
}
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)