This tutorial is out of date and no longer maintained.

Introduction

Angular Interceptors may be familiar to AngularJS developers, but Interceptors weren’t supported in early Angular versions. The Angular Interceptor was introduced in version 4.3 and is used to handle HTTP responses and requests. In this post, you will learn how to use the Angular 6 and 7 Interceptor to handle the HTTP request, response, and error handling.

Warning: Several of the packages in this tutorial now contain dependencies with known vulnerabilities. In a production setting you would resolve these issues by upgrading these packages, finding alternatives, or creating forked versions with patched fixes. However, within the limited context of a tutorial, it provides educational value as-is.



Prerequisites

To complete this tutorial, you will need:

Node.js installed locally, which you can do by following How to Install Node.js and Create a Local Development Environment.

Familiarity with creating Angular apps by using the Angular CLI.

At the time of writing, this tutorial used Node v8.12.0 and npm v6.4.1, but the tutorial has been verified with Node v14.2.0 and npm v6.14.4.

Note: This tutorial was written to connect to an sample API. However, the steps for creating and serving this backend is outside of the scope of this tutorial and left as an exercise to the reader.



Step 1 — Creating the Angular App

First, create a new Angular app named Angular-Interceptor with the CLI by running the following command in your terminal window:

npx @angular/cli@7.0.6 new Angular-Interceptor

You will be prompted to make a few selections for the project. For this tutorial, the following choices were selected:

Output Would you like to add Angular routing? Yes Which stylesheet format would you like to use? SCSS [ http://sass-lang.com ]

Next, navigate to your new project directory and serve the project:

cd Angular-Interceptor

npx ng serve --open

Then, view http://localhost:4200 in your browser to see the app. You’ve now configured a basic Angular app.

Step 2 — Styling the Angular App

Now that you’ve set up the basic project, let’s do a few things to enhance the user experience.

First you will add an Angular Material component for a better UI experience. You can find instructions on setting this up on the Angular Material Getting Started page

In your terminal window, run the following command to add @angular/material , @angular/cdk , and @angular/animations :

npm install --save @angular/material@7.0.4 @angular/cdk@7.0.4 @angular/animations@7.0.4

Next you will configure animations. Open the src/app/app.module.ts file in your code editor and add the following code to import BrowserAnimationsModule :

src/app/app.module.ts

... import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; @NgModule({ ... imports: [ ... BrowserAnimationsModule ], ... }) export class AppModule { }

Now you’re ready to import the component modules. Add the following code to import the MatDialogModule in your src/app/app.module.ts file:

src/app/app.module.ts

... import { MatDialogModule } from '@angular/material'; @NgModule({ ... imports: [ ... MatDialogModule ], ... }) export class AppModule { }

Let’s also add a theme to enhance the UI. Add indigo-pink.css to your styles.scss file:

src/styles.scss

@import "~@angular/material/prebuilt-themes/indigo-pink.css";

In this step you stylized your Angular app. In the next step, you will create an Interceptor.

Step 3 — Creating an Angular Interceptor

First, create a new interceptor folder under the app folder. Then create a new httpconfig.interceptor.ts file under the interceptor folder.

Import the following dependencies into your httpconfig.interceptor.ts file:

src/app/intreceptor/httpconfig.interceptor.ts

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

Note: In Angular 6 and 7, map was changed from rxjs/add/operator/map to rxjs/operators . You need to be careful while importing. These are the main changes in Angular 6 and 7.



Create a class HttpConfigInterceptor and implement the interface HttpInterceptor . This is an example:

@Injectable() export class HttpConfigInterceptor implements HttpInterceptor { intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> { // ... } }

You will set token , Content-Type , Accept type for an API request. Here is an example:

const token: string = localStorage.getItem('token'); request = request.clone({ headers: request.headers.set('Authorization', 'Bearer ' + token) }); request = request.clone({ headers: request.headers.set('Content-Type', 'application/json') }); request = request.clone({ headers: request.headers.set('Accept', 'application/json') });

You will need to handle the API response. This is an example:

map((event: HttpEvent<any>) => { if (event instanceof HttpResponse) { console.log('event--->>>', event); } return event; }),

Here’s the full code snippet:

src/app/interceptor/httpconfig.interceptor.ts

... @Injectable() export class HttpConfigInterceptor implements HttpInterceptor { intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> { const token: string = localStorage.getItem('token'); if (token) { request = request.clone({ headers: request.headers.set('Authorization', 'Bearer ' + token) }); } if (!request.headers.has('Content-Type')) { request = request.clone({ headers: request.headers.set('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; })); } }

Next, import the httpconfig.interceptor.ts in your AppModule .

src/app/app.module.ts

... import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http'; ... import { HttpConfigInterceptor } from './interceptor/httpconfig.interceptor'; @NgModule({ ... imports: [ ... HttpClientModule ], ... })

Then, add HttpConfigInterceptor to providers . To handle multiple interceptors, add multi: true .

src/app/app.module.ts

... @NgModule({ ... providers: [ ... { provide: HTTP_INTERCEPTORS, useClass: HttpConfigInterceptor, multi: true } ], ... }) ...

Step 4 — Creating a Service for Handling Errors

Now, you will create the errorDialogService to handle errors and display the error message for users.

Create a new error-dialog folder under the app folder. Under the error-dialog folder, create your errorDialogService files.

To handle the error response, create a new errordialog.service.ts file and add the code below:

src/error-dialog/errordialog.service.ts

import { Injectable } from '@angular/core'; import { MatDialog, MatDialogRef, MAT_DIALOG_DATA } from '@angular/material'; import { ErrorDialogComponent } from './errordialog.component'; @Injectable() export class ErrorDialogService { public isDialogOpen: Boolean = false; constructor(public dialog: MatDialog) { } openDialog(data): any { if (this.isDialogOpen) { return false; } this.isDialogOpen = true; const dialogRef = this.dialog.open(ErrorDialogComponent, { width: '300px', data: data }); dialogRef.afterClosed().subscribe(result => { console.log('The dialog was closed'); this.isDialogOpen = false; let animal; animal = result; }); } }

Next, create errordialog.component.ts to display the error dialog for the users:

src/error-dialog/errordialog.component.ts

import { Component, Inject } from '@angular/core'; import { MAT_DIALOG_DATA } from '@angular/material'; @Component({ selector: 'app-root', templateUrl: './errordialog.component.html' }) export class ErrorDialogComponent { title = 'Angular-Interceptor'; constructor(@Inject(MAT_DIALOG_DATA) public data: string) {} }

Then, create the errordialog.component.html template:

src/error-dialog/errordialog.component.html

<div> <div> <p> Reason: {{data.reason}} </p> <p> Status: {{data.status}} </p> </div> </div>

To handle the error response, you will need to revisit httpconfig.interceptor.ts .

Start with importing errordialog.service :

import { ErrorDialogService } from '../error-dialog/errordialog.service';

Add a constructor for errorDialogService :

constructor(public errorDialogService: ErrorDialogService) { }

The code below will handle the error response using catchError and throwError :

catchError((error: HttpErrorResponse) => { let data = {}; data = { reason: error && error.error && error.error.reason ? error.error.reason : '', status: error.status }; this.errorDialogService.openDialog(data); return throwError(error); })

Here’s the full code snippet:

src/app/interceptor/httpconfig.interceptor.ts

... import { ErrorDialogService } from '../error-dialog/errordialog.service'; ... @Injectable() export class HttpConfigInterceptor implements HttpInterceptor { constructor(public errorDialogService: ErrorDialogService) { } intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> { ... return next.handle(request).pipe( map((event: HttpEvent<any>) => { if (event instanceof HttpResponse) { console.log('event--->>>', event); } return event; }), catchError((error: HttpErrorResponse) => { let data = {}; data = { reason: error && error.error && error.error.reason ? error.error.reason : '', status: error.status }; this.errorDialogService.openDialog(data); return throwError(error); })); } }

Then, import errordialog.service and errordialog.component into the AppModule :

src/app/app.module.ts

... import { ErrorDialogComponent } from './error-dialog/errordialog.component'; ... import { ErrorDialogService } from './error-dialog/errordialog.service'; ... @NgModule({ ... declarations: [ ... ErrorDialogComponent ], ... providers: [ ... ErrorDialogService ], entryComponents: [ErrorDialogComponent], })

Step 5 — Creating a Sample Service File for HTTP Requests

In this example you will need a sample service file for API calls:

Login API

Customer Detail API

Make a new services folder under the src folder. Create a new login.service.ts file under the services folder. And add the functions to call two APIs.

src/services/login.service.ts

import { Injectable } from '@angular/core'; import { HttpClient } from '@angular/common/http'; @Injectable() export class LoginService { constructor(private http: HttpClient) { } login(data) { data = { email: 'admin', password: 'admin' }; return this.http.post(' http://localhost:3070/api/login ', data); } getCustomerDetails() { return this.http.get(' http://localhost:3070/customers/details '); } }

Note: In this example, there is a separate backend which is running in localhost:3070 .



Step 6 — Invoking the HTTP Client Service in the App Component

Add the two LoginService functions to app.component.ts . Call login API with onload and the customers/details with onclick.

src/app/app.component.ts

import { Component } from '@angular/core'; import { LoginService } from './services/login.service'; @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.scss'] }) export class AppComponent { title = 'Angular-Interceptor'; constructor(public loginService: LoginService) { this.loginService.login({}).subscribe(data => { console.log(data); }); } getCustomerDetails() { this.loginService.getCustomerDetails().subscribe((data) => { console.log('----->>>', data); }); } }

Also, add the element for the user to click on in app.component.html :

src/app/app.component.html

... <h2 (click)="getCustomerDetails()">Get customer details</h2>

Then, add LoginService to providers in your AppModule :

src/app/app.module.ts

... import { LoginService } from './services/login.service'; ... @NgModule({ ... providers: [ ... LoginService ] ... })

Here is a screenshot of the error handler dialog:

Conclusion

In this tutorial, you learned about how to handle the HTTP request and response using Angular 6 & 7 interceptors, along with how to handle the error using Angular Material dialog.