Applications with dynamic data call from REST API to get updated, these calls are mainly of POST or GET type. In Ionic 5 using Angular 9, we use HttpClientModule to make these POST or GET requests.
After Angular 4.3 the concept of Interceptors was introduced, using which we can override the HTTP calls to handle their requests and responses.
We can use Interceptors for many purposes like Handling Error responses, Internet connectivity intimations, show progress loaders, Add/ change header types of HTTP calls, secure server connectivity using token-based authentications, and many more.
In this post, we will learn How to make HTTP calls and handle their responses and request at one place using an Angular Interceptor.
We will create a new Ionic App using Angular latest stable version 7 using the latest Ionic CLI
Before we start make sure you have latest Ionic CLI installed
$ npm install -g @ionic/cli
Create new Ionic App
Run following NPM command in CMD to create a new Ionic application with a blank
template.
$ ionic start ionic-interceptor-app blank --type=angular
$ cd ionic-interceptor-app
Add HttpClientModule in App’s Module
To use HTTP services, we need to import HttpClientModule,
then add-in imports
array in the app.module.ts file as shown below.
//app.module.ts
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { RouteReuseStrategy } from '@angular/router';
import { IonicModule, IonicRouteStrategy } from '@ionic/angular';
import { SplashScreen } from '@ionic-native/splash-screen/ngx';
import { StatusBar } from '@ionic-native/status-bar/ngx';
import { AppComponent } from './app.component';
import { AppRoutingModule } from './app-routing.module';
import { HttpClientModule } from '@angular/common/http';
@NgModule({
declarations: [AppComponent],
entryComponents: [],
imports: [
BrowserModule,
IonicModule.forRoot(),
AppRoutingModule,
HttpClientModule
],
providers: [
StatusBar,
SplashScreen,
{ provide: RouteReuseStrategy, useClass: IonicRouteStrategy }
],
bootstrap: [AppComponent]
})
export class AppModule {}
Create an HTTP Interceptor
Now we will create an HTTP Interceptor to globally intercept and modify calls. Create a new file httpConfig.interceptor.ts and replace the below code in it.
Interceptors implements
HttpInterceptor service to override the intercept method taking two parameters HttpRequest
and HttpHandler.
//httpConfig.interceptor.ts
import {
HttpRequest,
HttpHandler,
HttpEvent,
HttpInterceptor,
HttpResponse,
HttpErrorResponse
} from '@angular/common/http';
import { Observable, throwError } from 'rxjs';
import { map, catchError } from 'rxjs/operators';
import { Injectable } from '@angular/core';
@Injectable()
export class HttpConfigInterceptor implements HttpInterceptor {
constructor() { }
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
const token = "my-token-string-from-server";
//Authentication by setting header with token value
if (token) {
request = request.clone({
setHeaders: {
'Authorization': token
}
});
}
if (!request.headers.has('Content-Type')) {
request = request.clone({
setHeaders: {
'content-type': 'application/json'
}
});
}
request = request.clone({
headers: request.headers.set('Accept', 'application/json')
});
return next.handle(request).pipe(
map((event: HttpEvent<any>) => {
if (event instanceof HttpResponse) {
console.log('event--->>>', event);
}
return event;
}),
catchError((error: HttpErrorResponse) => {
console.error(error);
return throwError(error);
}));
}
}
As we can’t directly change headers of the request so we make a clone of request.
To use this interceptor globally we need to import this in the app.module.ts file and also add in providers array as shown below.
//app.module.ts
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { RouteReuseStrategy } from '@angular/router';
import { IonicModule, IonicRouteStrategy } from '@ionic/angular';
import { SplashScreen } from '@ionic-native/splash-screen/ngx';
import { StatusBar } from '@ionic-native/status-bar/ngx';
import { AppComponent } from './app.component';
import { AppRoutingModule } from './app-routing.module';
import {
HTTP_INTERCEPTORS,
HttpClientModule
} from '@angular/common/http';
import { HttpConfigInterceptor } from './httpConfig.interceptor';
@NgModule({
declarations: [AppComponent],
entryComponents: [],
imports: [
BrowserModule,
IonicModule.forRoot(),
AppRoutingModule,
HttpClientModule
],
providers: [
StatusBar,
SplashScreen,
{ provide: RouteReuseStrategy, useClass: IonicRouteStrategy },
{
provide: HTTP_INTERCEPTORS,
useClass: HttpConfigInterceptor,
multi: true
}
],
bootstrap: [AppComponent]
})
export class AppModule {}
Show Ionic Loader Spinner on HTTP request
Using Interceptors we can easily show/ hide Ionic Spinner loader at one place. We will import LoadingController and use it show/hide in the interceptor callbacks. You can check more details on loaders here
//httpConfig.interceptor.ts
import {
HttpRequest,
HttpHandler,
HttpEvent,
HttpInterceptor,
HttpResponse,
HttpErrorResponse
} from '@angular/common/http';
import { Observable, throwError } from 'rxjs';
import { map, catchError } from 'rxjs/operators';
import { Injectable } from '@angular/core';
import { LoadingController } from '@ionic/angular';
@Injectable()
export class HttpConfigInterceptor implements HttpInterceptor {
loaderToShow: any;
constructor(
public loadingController: LoadingController
) { }
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
const token = "my-token-string-from-server";
//Authentication by setting header with token value
if (token) {
request = request.clone({
setHeaders: {
'Authorization': token
}
});
}
if (!request.headers.has('Content-Type')) {
request = request.clone({
setHeaders: {
'content-type': 'application/json'
}
});
}
request = request.clone({
headers: request.headers.set('Accept', 'application/json')
});
this.showLoader();
return next.handle(request).pipe(
map((event: HttpEvent<any>) => {
if (event instanceof HttpResponse) {
console.log('event--->>>', event);
}
this.hideLoader();
return event;
}),
catchError((error: HttpErrorResponse) => {
console.error(error);
this.hideLoader();
return throwError(error);
}));
}
showLoader() {
this.loaderToShow = this.loadingController.create({
message: 'Processing Server Request'
}).then((res) => {
res.present();
res.onDidDismiss().then((dis) => {
console.log('Loading dismissed!');
});
});
this.hideLoader();
}
hideLoader() {
this.loadingController.dismiss();
}
}
Create a service HttpService
After adding the Interceptor, we will create a new service that will method to make an HTTP call to test our Interceptor response handling.
Create new service HttpService
and replace the below code:
// http.service.ts
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable, of } from 'rxjs';
import { catchError, tap } from 'rxjs/operators';
@Injectable({
providedIn: 'root'
})
export class HttpService {
apiUrl = 'https://localhost:8080/api/getdetails';
constructor(private http: HttpClient) { }
getDetails(): Observable<any> {
return this.http.get(this.apiUrl)
.pipe(
tap(_ => this.log('response received')),
catchError(this.handleError('getDetails', []))
);
}
private handleError<T>(operation = 'operation', result?: T) {
return (error: any): Observable<T> => {
// TODO: send the error to remote logging infrastructure
console.error(error); // log to console instead
// TODO: better job of transforming error for user consumption
this.log(`${operation} failed: ${error.message}`);
// Let the app keep running by returning an empty result.
return of(result as T);
};
}
/** Log a HeroService message with the MessageService */
private log(message: string) {
console.log(message);
}
}
Finally, in Home component replace following class and template code:
home.page.html
<ion-header>
<ion-toolbar>
<ion-title>
Ionic HTTP
</ion-title>
</ion-toolbar>
</ion-header>
<ion-content>
<ion-button (click)="employeeDetails()">
Click me
</ion-button>
</ion-content>
home.page.ts
// home.page.ts
import { Component } from '@angular/core';
import { HttpService } from '../http.service';
@Component({
selector: 'app-home',
templateUrl: 'home.page.html',
styleUrls: ['home.page.scss'],
})
export class HomePage {
constructor(private httpService:HttpService) { }
employeeDetails(){
this.httpService.getDetails().subscribe(books => {
console.log(books);
});
}
}
So now we have an Interceptor in Ionic 4 application which is helping in modifying get requests by changing headers and also setting token in the Authentication key. We are also handling errors in Interceptors which can be logged for debugging purposes.
Leave a Reply