Error handling in 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â, assurance, 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;
npm i -g @angular/cli
With all these prerequisites in place, we can start by creating a new folder for our application.
ng new my-ErrorHandling-app
ng serve -o
This will open the application in your local browser on localhost:4200, you should see this
Error in Angular application can either be a Client-Side error or Server-Side error;
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.
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
JsCopy
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?
So, what have I done?
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();
}
JsCopy
Now, save your code and click on the button, you should see a joke object on your browserâs console.
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.
1.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);
}
}
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â
JsCopy
We need to import the retry and catchError operators from rxjs/operators. retrywill 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 .
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.
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 source code here
*Originally published by Sulaiman at dunebook.com
===============================================================
Follow me on Facebook | Twitter
â Angular 7 (formerly Angular 2) - The Complete Guide
â Learn and Understand AngularJS
â The Complete Angular Course: Beginner to Advanced
â Angular Crash Course for Busy Developers
â Angular Essentials (Angular 2+ with TypeScript)
â Angular (Full App) with Angular Material, Angularfire & NgRx
â Angular & NodeJS - The MEAN Stack Guide
#angular