Global error handling in angular 6 with HttpClient & interceptor

angular 6 http error handling angular 5 http error handling angular 4 global http error handler angular interceptor error handler error handling best practices http error handling best ways http error handling best practices angular 2 global http error handler

Angular 4.3.1 introduced HttpInterceptor, we will use HttpClient and new HttpInterceptor feature to handle error globally for entire application.

When calling the service method, we might get some kind of server error. It can be any kind, like poor network connection to reach to the server, method itself through error due to any logical error, or unable to connect to the database, in that case HttpClient will return error object instead of a successful response. Let's see how we can catch error in component:

this.custService.getCustomers()
    .subscribe(
      response => {
        this.customers = response
      },
      error => {
        this.error = error    
      });

And we can bind the error on page to show it, simple.

<div class="row">
    <div class="col-sm-12 alert alert-warning">
    {{error}}
  </div>
</div>

Handle error in services:

Before returning error to component it's always better to compose the error in a user freindly manner.

There are two types of errors:

  • Server Side Error: Logic Error, 404, 500, Unable to read file, Unable to connect to database etc. These are error responses.
  • Client Side Error: network error, Exception thrown from RxJS etc. These errors produce JavaScript ErrorEvent objects.

Luckily HttpClient capture both kind of error in it's HttpErrorResponse and we can inspect that response to figure out what really happened.

private handleError(error: HttpErrorResponse) {
    let errMsg = '';
    // Client Side Error
    if (error.error instanceof ErrorEvent) {        
      errMsg = `Error: ${error.error.message}`;
    } 
    else {  // Server Side Error
      errMsg = `Error Code: ${error.status},  Message: ${error.message}`;
    }
    // return an observable
    return throwError(errMsg);
};

Everything works well and looks simple, but the problem here is, we need to copy this handerError(...) method to every service which is against DRY(don't repeat yourself) rule. In future if we need to change anything, we need to change in every service, which is not good.

There are two way to put it on a single place

  • Create a base service and extend all the services with our base service
  • Use the interceptor

Second option is easier and Angular way to implement common error handler for entire application globally.

So what is Interceptor in Angular? This feature was not in angular 2, 3 & 4 but added in Angular 4.3.1. Interceptor is a mechanism to modify the request/response before sending to the server (request) or to client (response). There are many things we can do like add/remove header, add logged in token, update the response like change the error, format is properly before sending to the client are some examples.

Here is the interface provided be Angular team HttpInterceptor which we are going to implement in our ErrorHandler interceptor:

interface HttpInterceptor {
  intercept(req: HttpRequest<any>, next: HttpHandler): 
        Observable<HttpEvent<any>>
}

Since we need only to handle the error so we will not talk how to add or remove headers through interceptor. What we are going to do is, move your errorHandler from the service to this ErrorHandler interceptor. Crate a new file in the same folder where we have our app.module.ts file and give any name, say "error-handler.ts" and add following code in it:

import { HttpEvent, 
         HttpInterceptor, 
         HttpHandler, 
         HttpRequest, 
         HttpResponse,
         HttpErrorResponse} from '@angular/common/http';
import { Observable, throwError } from 'rxjs';
import { catchError } from 'rxjs/operators';

export class HttpErrorInterceptor implements HttpInterceptor {
  intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>>{
    return next.handle(request)
       .pipe(
         catchError( (error: HttpErrorResponse) => { 
            let errMsg = '';
            // Client Side Error
            if (error.error instanceof ErrorEvent) {        
              errMsg = `Error: ${error.error.message}`;
            } 
            else {  // Server Side Error
              errMsg = `Error Code: ${error.status},  Message: ${error.message}`;
            }
            return throwError(errMsg);
          })
       )
  }
}   

Point to note,

  • Given our interceptor class name HttpErrorInterceptor, it can be any thing
  • We are implementing HttpInterceptor
  • We implemented intercept method
  • Rest of the code is same copied from our service, which we already know

Just creating and interceptor will now start working, we need to add it into provides in our app.module. So open app.module file and adjust the code:

import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http'; 
import { HttpErrorInterceptor } from './error-interceptor';

@NgModule({
  imports: [...], 
  declarations: [...],
  bootstrap:    [....],
  providers: [
    {
      provide: HTTP_INTERCEPTORS,
      useClass: HttpErrorInterceptor,
      multi: true,
    },
    CustomerService,...]
}) 

Here I removed rest of the code and keep only those we need to change, see the providers.

Open the customer menu and you can see the result as a returned JSON or error with code and error message.

Now our interceptor is ready to take care about any Http issue, so we don't need any more code in service. Go ahead and remove errorHandler entire function from there.

We also don't need to catch error in service any more, remove the service code to catch the error, now our service code will be very straight forward and simple:

getCustomers(){ return this.http.get("service method url");
}

Pages wherever we are calling this service method still we need to check the error, if there is any, asign to a variable and show on the page. I am using only with customer lists page:

// Inside the customer-list.component.ts file
ngOnInit(){    
  this.custService.getCustomers()
    .subscribe(
      response =>  this.customers = response,
      error => this.error = error
    );
}
// inside the html file
<div class="row" *ngIf="error.length > 0">
    <div class="col-sm-12 alert alert-warning">
    {{error}}
  </div>
</div>

On customers list page let's add some valid and invalid Url and a link to call the service to show the json result or error. I did the show/hide of error and result after 2 second and 4 second that's is not needed just to show our code is working as we want.

Now everything is working good, can we still improve it? Of course, I don't like to add error show/hide html and remember what variable I used and what I am showing on the page. We can go ahead and try to add a new component to show the message for entire application from any page (component).

We will cover notification for entire application in next article.

Ali Adravi Having 13+ years of experience in Microsoft Technologies (C#, ASP.Net, MVC and SQL Server). Worked with Metaoption LLC, for more than 9 years and still with the same company. Always ready to learn new technologies and tricks.
  • angular
  • angularjs
  • httpclient
  • httpinterceptor
By Ali Adravi On 10 Aug, 18  Viewed: 2,282

Other blogs you may like

Angularjs powerful paging on table and searching with delay and demo

Paging on table is the basic requirement and most of us look for some grid so it can provide the complete feature of paging and sorting but in Angularjs it is so easy that anyone can achieve it by writing some code. I checked and found most of the available code give the paging feature in for 1 to... By Ali Adravi   On 14 Aug 2015  Viewed: 13,628

Angularjs Cascading Dropdown/Select with demo

Cascading dropdown with angularjs is easier than MVC and ASP.Net. In Angularjs ng-change is the best event to hook the function to get the second dropdown list items. In this article, we will try to fill the state dropdown on selection change of country and then fill the city dropdown on change... By Ali Adravi   On 06 Aug 2015  Viewed: 48,429

Angularjs CRUD with Web API, Entity Framework & Bootstrap modal popup part 2

Add/Edid Customer in Modal Popup --- In previous article we discussed how to search, delete and show detail of customer and contact list. In this article we will try to open the modal popup to add new customer and edit an existing customer record. I divided article in two parts because of the... By Ali Adravi   On 29 Jul 2015  Viewed: 17,427

Custom Directives in AngularJS with example and demo

Angularjs custom directives are the common to avoid the duplicate code, it is easy powerful and really nice. There are already too many directive have been created by experts but as a developer we need to write our own to achieve our specific goal. ng-model, ng-if, ng-show, ng-repeat all these are... By Ali Adravi   On 29 Jul 2015  Viewed: 3,886

Angularjs CRUD with Web API, Entity Framework & Bootstrap modal popup part 1

Search sort Insert update and delete are the basic features we need to learn first to learn any language, In this article we will try to create these features with Web API, bootstrap modal popup and ui.router. We will use enetity framework code first to save and retrieve data from database. We... By Ali Adravi   On 28 Jul 2015  Viewed: 28,855