Error Handling in Angular Applications

Error Handling in Angular Applications


Error handling in Angular or  software development is as important having a working application.

In order to have a complete and robust application, errors and exceptions have to be properly handled.

Handling errors is a way of telling your users “hey dude! Calm down, here is the problem, and here is the way out yeah?

In this tutorial, I will walk you through how to efficiently handle errors in your Angular Application. I will be using latest version of  Angular 7.0.4 for this tutorial and I will advise you use the same.

Prerequisites

For the purpose of this tutorial the following has to be available on your system;

Install Node

  • Go to nodejs
  • Download and install the available LTS version.
  • To check your version, run node -v in a terminal/console window.

Install Angular CLI

 npm i -g @angular/cli 

 I use Angular IDE but you can choose to use any other IDE like VsCode, Atom, Vim etc.

With all these prerequisites in place, we can start by creating a new folder for our application.

    • Open your Angular IDE and Right click on files option.
    • Now from the project wizard select the create a new angular project and insert project name
            my-ErrorHandling-app 
      
    • The Angular Ide Wizard prompts you for information about features to include in the initial app project. Accept the defaults by pressing the Enter or Return key.
    • Serve the application locally by clicking servers View tab in angular IDE, alternatively you can use the following command.
            ng serve -o 
      

This will open the application in your local browser on localhost:4200, you should see this Angular

Error in Angular application can either be a Client-Side error or Server-Side error;

  • Client-side error: These are errors related to Front-end code and the Network, they throw 4xx status codes.
  • Server-side error: These are errors related to Back-end codes, database and file system. They usually throw 5xx status codes.

For the purpose of this tutorial, we are going to demo error handling by consuming chucknorris API to display random jokes using Angular’s in-built HttpClientModule.

We start by importing HttpClientModule to our root module (app.module.ts).

       import { BrowserModule } from '@angular/platform-browser';
       import { NgModule } from '@angular/core';
       import { HttpClientModule } from '@angular/common/http';
       import { AppRoutingModule } from './app-routing.module';
       import { AppComponent } from './app.component';

      @NgModule({
        declarations: [
          AppComponent
       ],
       imports: [
          BrowserModule,
          HttpClientModule,
          AppRoutingModule
      ],
       providers: [],
       bootstrap: [AppComponent]
      })
      export class AppModule { }

In app.component.html, we create a button which will initiate an http request on click.

button

In app.component.ts, we include our constructor function and extend the component’s class to implement OnInit lifecycle hook.

       
  import {Component, OnInit} from '@angular/core';

  @Component ({
    selector: 'app-root',
    templateUrl: './app.component.html',
    styleUrls: ['./app.component.scss']
  })
  export class AppComponent implements OnInit {
    title = 'my-app';
constructor () {}

  makeApiCall () {  
  }

  ngOnInit () {}
   }

Now we need to create a service where we will make our http request. Service is a very important component of Angular. When we need to have some codes to be used everywhere in the application or we need to pass data across the application, services will come in handy.

ng g service appService

This will create a new Injectable service that can be injected into all our components. We should have this on our folder tree now.

After creating the service, we will inject the service into app component controller (app. component.ts file). Notice how the appService is imported into the component.

       
  import {Component, OnInit} from '@angular/core';
  import {AppServiceService } from './app-service.service';
  @Component ({
     selector: 'app-root',
     templateUrl: './app.component.html',
     styleUrls: ['./app.component.scss']
  })
  export class AppComponent implements OnInit {
  	title = 'errorHandling-app';
  	constructor (appService: AppServiceService) {
          }
	ngOnInit() {}
}

In the appService, we will make our http request to chuck Norris open API to get random jokes.

       
    import { Injectable } from '@angular/core';
  import { HttpClient } from '@angular/common/http';

  @Injectable ({
    providedIn: 'root'
  })
  export class AppServiceService {
  base_Url = 'https://api.chucknorris.io/jokes';

  constructor (private  http: HttpClient) { }

  getJokes (): Observable {
    return this.http.get(`${ this.base_Url }/random`)
  }

  extractJokes () {
    this.getJokes ().subscribe(res => {
      console.log(res);
      })
    }
  }

So, what have I done?

  • I set the base URL for our API to https://api.chucknorris.io/jokes
  • I injected HttpClient service as a private variable in the constructor function. N.B. You need to import HttpClientModule into app.module.ts from @angular/common/http
  • I created a getJokes that invokes the http get method to fetch random jokes. This is returned as Observables.
  • In the extractJokes method, I subscribe to the jokes Observable and logging it on the console.

Well, I think the next thing we need to do is to call the extractJokes method from controller on click of the button. In the makeApi method, insert this;


      makeApiCall() {
         this.appService.extractJokes();
       }

Now, save your code and click on the button, you should see a joke object on your browser’s console.

Error handling in Angular

Works fine right? 🙂

We are done with the application and ready to ship. Oh wait!!! What happens if there is any error from our http request, how do we let the user know of the error, how do we handle that.

Now there are many ways of doing this, in the next chapter of this tutorial, let’s explore some of them.

  ERROR HANDLING

We can use error handler that will alert the user of the error

       
            import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable, throwError } from 'rxjs';
import { map, retry, catchError } from 'rxjs/operators'

@Injectable({
  providedIn: 'root'
})
export class AppServiceService {
  base_Url = 'https://api.chucknorris.io/jokes';

  constructor(private  http: HttpClient) { }

  getJokes(): Observable {
    return this.http.get(`${this.base_Url}/random`)
  }


  extractJokes() {
    this.getJokes ().subscribe(res => {
      console.log(res);
    },
    err => {
      console.log(err);
      this.handleError (err.message);
    });
  }

  handleError (err) {
    alert(err);
  }
}

I created a new handleError method that alerts the user of the error, I also added a second argument which takes the error , log it to browser’s console and invoke the handleError function with the error passed as argument.

Now let’s simulate an error scenario, take your browser offline and click the button to test.

Error handling in AngularNotice how I turned my browser offline. You should get an alert like this

Error handling in Angular

This tells us that there is an http failure response. Now the user knows about the error, better, yeah? J, but we can do better.

Now let’s re-jig our code. Starting with getJokes method in our service.

import { retry, catchError } from 'rxjs/operators'

We need to import the retry and catchError operators from rxjs/operators. retry will help us retry the http request as many times as specified before throwing error, catchError will throw the error to the user.

Now modify the getJokes, extractJokes and handleError methods as shown below;


    getJokes (): Observable {
    	return this.http.get(`${this.base_Url}/random`)
    	.pipe (
      	retry (3),
      	catchError(this.handleError)
    	)
  	}
	
     extractJokes () {
        this.getJokes (). subscribe(res => {
     	 console.log(res);
   	 });
 	 }

      handleError(err) {
    	let errorMessage = '';
    	if (err.error instanceof ErrorEvent) {
      	// if error is client-side error
      	errorMessage = `Error: ${err.message}`;
    	} else {
      	// if error is server-side error
      	errorMessage = `Error Code: ${err.status}\nMessage: ${err.message}`;
    	}
    	alert(errorMessage);
    	return throwError(errorMessage);
  	}

Remember I stated earlier that errors could either be client or server error, so we need to catch whichever one that happens. So whenever we click the button to make the http request, we have successfully handle whichever kind of error that occurs.

The second way of handling error is with the use of HttpInterceptor which was introduced with Angular 4.3.1. HttpInterceptor is used to intercept all http requests and responses and optionally transform it. HttpInterceptor is an interface that can be implemented by a class, it has an intercept method which takes all the logic to be implemented when the http requests get intercepted. You can read more from the official angular documentation .

  • Create a new class HttpInterceptor.ts

  import { HttpInterceptor, HttpEvent, HttpHandler, HttpRequest } from '@angular/common/http';
  import { Observable } from 'rxjs';
  import { Injectable } from '@angular/core';

 @Injectable ({
    providedIn: 'root'
  })
  export class HttpInterceptorClass  implements HttpInterceptor {
      intercept (req: HttpRequest, next: HttpHandler): Observable<HttpEvent> {
        console.log('Intercepted');
        return next.handle (req);
    }
  }

We need to add the new class to the list of providers in app module.


import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http';
import { HttpInterceptorClass } from  './HttpInterceptor';

providers: [
    	{
      		provide: HTTP_INTERCEPTORS,
      		useClass: HttpInterceptorClass,
      		multi: true
    	}

  	],

Notice how HTTP_INTERCEPTORS was imported form @angular/common/http If you click the button to make the http request, the request will be intercepted and ‘intercepted’ will be logged to the browser’s console.

Error handling in Angular

Yaay, we have now been able to intercept all our request and successfully log a message to the console on every request. With this we can put in our error handling logic here. Edit the HttpInterceptor file as shown below


    export class HttpInterceptorClass  implements HttpInterceptor {
    intercept(req: HttpRequest, next: HttpHandler): Observable<HttpEvent> {
      console.log('Intercepted');
      return next.handle(req)
      .pipe(
        retry (3),
        catchError (( err : HttpErrorResponse) => {
          let errorMessage = '';
          if (err.error instanceof ErrorEvent) {
            // client-side error
            errorMessage = `Error: ${err.message}`;
          } else {
            // server-side error
            errorMessage = `Error Code: ${err.status}\nMessage: ${err.message}`;
          }
          alert(errorMessage);
          return throwError(errorMessage);
        })
      )
    }
}

Using HttpInterceptor allows us to have a proper separation of concerns which is exactly what Angular preaches as best practice. If we want to change the way we push error to the user in any part of our application, we can simply do that in the Interceptor class created, this way we can handle errors properly and globally within the application.

Here we come to the end of the tutorial, we have been able to demonstrate different ways of handling errors in our angular application.

You can access the Code Source  here


Share on social media

//