Friday, 10 January 2020

Angular HttpClient Error Handling




We have to add an error handling to handle any error on every HttpClient requests. To do that, simply open and edit `src/app/api.service.ts` then add this function that handles the error in a simple way.


private handleError<T>(operation = 'operation', result?: T) {
  return (error: any): Observable<T> => {
    console.error(error);
    this.log(`${operation} failed: ${error.message}`);

    return of(result as T);
  };
}

private log(message: string) {
  console.log(message);
}
In the above codes, we are creating 2 functions for handle error and print log of error. There are the new required modules, so, add it to existing imports.
import { Observable, of } from 'rxjs';
Next, add a HttpClient request function with catchError.
getSmartphone(): Observable<any> {
  return this.http.get<Smartphone[]>(localUrl).pipe(
    catchError(this.handleError<Smartphone[]>('getSmartphone', [])));
}
Change the get data function in the component to this function.
getSmartphones() {
  this.api.getSmartphone()
    .subscribe(data => {
      console.log(data);
    });
}
Another way to handle the error is by using HttpInterceptor. To do that, create a new folder `src/app/interceptors` and an HttpErrorInterceptor file.
mkdir src/app/interceptors
touch src/app/interceptors/HttpErrorInterceptor.ts
Next, open and edit `src/app/interceptors/HttpErrorInterceptor.ts` then add these imports of RxJS Observable, throwError, catchError, tap, Angular Common Http HttpInterceptor, HttpRequest, HttpHandler, HttpEvent, and HttpErrorResponse.
import { catchError, tap } from 'rxjs/internal/operators';
import { Injectable } from '@angular/core';
import { HttpInterceptor, HttpRequest, HttpHandler, HttpEvent, HttpErrorResponse } from '@angular/common/http';
import { Observable, throwError } from 'rxjs';
Add these Typescript class that intercepts error from the HttpRequest.
@Injectable()
export class HttpErrorInterceptor implements HttpInterceptor {
  intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    return next.handle(request)
      .pipe(
        tap(data => console.log(data)),
        catchError((error: HttpErrorResponse) => {
          if (error.error instanceof ErrorEvent) {
            // A client-side or network error occurred. Handle it accordingly.
            console.error('An error occurred:', error.error.message);
          } else {
            // The backend returned an unsuccessful response code.
            // The response body may contain clues as to what went wrong,
            console.error(
              `Backend returned code ${error.status}, ` +
              `body was: ${error.error}`);
          }
          // return an observable with a user-facing error message
          return throwError(
            'Something bad happened; please try again later.');
        })
      );
  }
}
Next, open and edit `src/app/app.module.ts` then add this import of Angular Common Http HttpInterceptor and HttpErrorInterceptor that previously created.
import { HTTP_INTERCEPTORS } from '@angular/common/http';
import { HttpErrorInterceptor } from './interceptors/HttpErrorInterceptor';
Add them to the @NgModule provider's array.
providers: [
  {
    provide: HTTP_INTERCEPTORS,
    useClass: HttpErrorInterceptor,
    multi: true,
  }
],
You can use Retry function to retry the HttpRequest after an error is occurred to make sure the HTTP request is a real error. Add this function after the pipe function inside HttpErrorInterceptor or service function.
getSmartphone(): Observable<any> {
  return this.http.get<Smartphone[]>(localUrl).pipe(
    retry(3), catchError(this.handleError<Smartphone[]>('getSmartphone', [])));
}
Don't forget to modify existing RxJS import.
import {catchError, retry} from 'rxjs/internal/operators';
Share: