Angular Error Interceptor

By Arvind Rai, 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 using HttpInterceptorFn.
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.'));
        })
    );
} 
When a request fails, 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 provide HttpClient, 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.'));
    })
  );
} 
Find a simple global error component.
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 {
} 
Create routes.
app.routes.ts
import { Routes } from '@angular/router';
import { GlobalErrorComponent } from './global-error.component';

export const ROUTES: Routes = [
     ------
    { path: 'globalError', component: GlobalErrorComponent }
]; 
Configure interceptors and router.
app.config.ts
export const appConfig: ApplicationConfig = {
  providers: [
    provideHttpClient(withInterceptors([myErrorInterceptor])),
    provideRouter(ROUTES),
    ------
  ]
}; 

4. Reference

POSTED BY
ARVIND RAI
ARVIND RAI







©2024 concretepage.com | Privacy Policy | Contact Us