This tutorial is out of date and no longer maintained.
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.
To complete this tutorial, you will need:
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.
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:
OutputWould 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.
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
:
...
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:
...
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:
@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.
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:
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:
...
@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
.
...
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
.
...
@NgModule({
...
providers: [
...
{ provide: HTTP_INTERCEPTORS, useClass: HttpConfigInterceptor, multi: true }
],
...
})
...
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:
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:
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:
<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:
...
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
:
...
import { ErrorDialogComponent } from './error-dialog/errordialog.component';
...
import { ErrorDialogService } from './error-dialog/errordialog.service';
...
@NgModule({
...
declarations: [
...
ErrorDialogComponent
],
...
providers: [
...
ErrorDialogService
],
entryComponents: [ErrorDialogComponent],
})
In this example you will need a sample service file for API calls:
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.
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
.
Add the two LoginService
functions to app.component.ts
. Call login
API with onload and the customers/details
with onclick.
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
:
...
<h2 (click)="getCustomerDetails()">Get customer details</h2>
Then, add LoginService
to providers
in your AppModule
:
...
import { LoginService } from './services/login.service';
...
@NgModule({
...
providers: [
...
LoginService
]
...
})
Here is a screenshot of the error handler dialog:
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.
You can find the sample code on GitHub. You can git clone
, npm install
, and npx ng server
to run the sample code. Don’t forget to change the backend API URL in the login.service.ts
file.
Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.
This textbox defaults to using Markdown to format your answer.
You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!