Angular Error Interceptor
February 01, 2024
On this page, I will create a HTTP interceptor that will handle error when a URL fails or return server error. HTTP interceptors are applied on HttpClient
. Using interceptor we can create a global error handler for HTTP operations.
In HTTP error handling, we use RxJS operators, some of them are as below.
retry : Resubscribe to the source stream for the given number of time, when there is error.
catchError : Catches error to handle and returns new observable or throws error.
throwError : Creates an observable for error to be thrown when subscribed.
HttpErrorResponse : Represents an error or failure. They can be of two types.
1. Error could be because of network failure on client side and hence request will not complete successfully. In this case,
HttpErrorResponse
will have following value.
The property status will hold 0.
The property error will hold
ProgressEvent
instance.
2. Server backend may throw exception and return error codes such as 404, 500 etc.
HttpInterceptorFn : To intercept
HttpRequest
or HttpResponse
, we create interceptors. Here we will create functional interceptor using HttpInterceptorFn
.
export const myErrorInterceptor: HttpInterceptorFn = (req: HttpRequest<unknown>, next: HttpHandlerFn) => { return next(req); }
1. Create Error Interceptor
Here I will create a functional interceptor usingHttpInterceptorFn
.
error-interceptor.ts
import { HttpRequest, HttpInterceptorFn, HttpHandlerFn, HttpErrorResponse } from '@angular/common/http'; import { throwError } from 'rxjs'; import { catchError, retry } from 'rxjs/operators'; export const myErrorInterceptor: HttpInterceptorFn = (req: HttpRequest<unknown>, next: HttpHandlerFn) => { return next(req).pipe( retry(2), // retry a failed request up to 2 times catchError((err: HttpErrorResponse) => { if (err.status === 0) { //client-side or network error console.log('An error occurred:', err.error.message); // return of() } else { //Backend returns error codes such as 404, 500 etc. console.log('Error code: ', err.status); } return throwError(() => new Error('An error occurred. Please try again later.')); }) ); }
retry(2)
will try for two times for consecutive failure. At last if request could not completed successfully, catchError
will catch error. Here I am checking if error is because of network or server backend and logging accordingly. Finally using throwError
, I am throwing error with custom error message.
We can also use
switch
statement to handle error by error code.
catchError((err: HttpErrorResponse) => { switch (err.status) { case 0: console.log("Network error"); break; case 400: console.log("400 Bad Request. Server cannot process the request"); break; ------ } return throwError(() => new Error('An error occurred. Please try again later.')); })
2. Configure Interceptor
In Angular standalone application, to provideHttpClient
, use provideRouter()
and to configure functional interceptor, use withInterceptors()
.
app.config.ts
import { provideHttpClient, withInterceptors } from '@angular/common/http'; import { myErrorInterceptor } from './http-interceptors/error-interceptor'; export const APP_CONFIG: ApplicationConfig = { providers: [ provideHttpClient(withInterceptors([myErrorInterceptor])), ------ ] };
3. Redirect to Global Error Page
Using interceptor, we can also redirect to a global error page when application encounters an error.Find the code.
error-interceptor.ts
import { HttpRequest, HttpInterceptorFn, HttpHandlerFn, HttpErrorResponse } from '@angular/common/http'; import { inject } from '@angular/core'; import { Router } from '@angular/router'; import { throwError } from 'rxjs'; import { catchError } from 'rxjs/operators'; export const myErrorInterceptor: HttpInterceptorFn = (req: HttpRequest<unknown>, next: HttpHandlerFn) => { const router: Router = inject(Router); return next(req).pipe( catchError((err: HttpErrorResponse) => { switch (err.status) { case 0: console.log("Network error"); break; case 400: console.log("400 Bad Request. Server cannot process the request"); break; case 401: console.log("401 Authentication Error"); break; case 500: console.log("500 Internal Server Error"); break; default: console.log(err.url); console.log(err.status + ", " + err.statusText); break; } router.navigateByUrl("globalError"); return throwError(() => new Error('An error occurred. Please try again later.')); }) ); }
global-error.component.ts
import { Component } from '@angular/core'; @Component({ standalone: true, template: ` <h3>An error occurred. Please try again later.</h3> ` }) export class GlobalErrorComponent { }
app.routes.ts
import { Routes } from '@angular/router'; import { GlobalErrorComponent } from './global-error.component'; export const ROUTES: Routes = [ ------ { path: 'globalError', component: GlobalErrorComponent } ];
app.config.ts
export const appConfig: ApplicationConfig = { providers: [ provideHttpClient(withInterceptors([myErrorInterceptor])), provideRouter(ROUTES), ------ ] };