How to build a HTTP Interceptor in Angular 5

November 8, 2017

Introduction

A HTTP Interceptor enables you to catch HTTP requests and responses so that you can modify them. It is very useful especially when you want to add extra headers to all outgoing requests or catch error responses from the server. One use case scenario for an interceptor is adding authorization header for authentication to all request.

You could add an authorization header manually to all requests but that would be a lot of work. Or you could automatically intercept and append the header before sending the request to the server. Another use case scenario is handling errors and caching of content. You can use an interceptor to catch errors and log them or serve cached content to the user instead of getting content from the server.

We are going to build a simple Interceptor that will catch-all outgoing requests and incoming responses and log them in console. You can view the console of your browser by opening the developers’ tools.

Getting Started

First, we are going to create a new Angular 5 Application using Angular CLI.

ng new httpinterceptor

A new directory will be created known as httpinterceptor. This is the location of your newly created project. You can run the application and the output would look like this: How to build a HTTP Interceptor in Angular 5 We shall use JSON PlaceHolder as our endpoint to make our http requests. This is a Fake Online REST API for Testing and Prototyping. It has several variations of http requests which we can call expecting different results, it’s also free. To make any http requests we need to import the HttpClientModule into our application in the app.module.ts.

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

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

Next, we need to add two buttons in our app.component.html file. The two buttons will call different methods on click. The first method will call an genuine URL while the second one will call a bogus URL that doesn’t exist hence triggering an error. Replace everything in the file with the following:

<div style="text-align:center">
  <h1>Click one of the two buttons</h1>
  <button (click)="method1Call()">Method 1</button>
  <button (click)="method2Call()">Method 1</button>
</div>

Now that we have a user interface, we need to add the two methods to our app.component.ts and import HTTPClient.

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

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  title = 'app';
  constructor(private httpClient: HttpClient) {}

  method1Call(): void {
    this.httpClient
      .get('https://jsonplaceholder.typicode.com/users')
      .subscribe(success => {
        console.log('Successfully Completed');
        console.log(success);
      });
  }

  method2Call(): void {
    this.httpClient
      .get('https://jsonplaceholder.typicode.com/user12')
      .subscribe(success => {
        console.log('Successfully Completed');
        console.log(success);
      });
  }
}

We expect the first request to succeed but the 2nd one to fail. Instead of using the fail method inside a subscribe method, we will use the interceptor to catch the errors and log them. Here are the results so far.

How to build a HTTP Interceptor in Angular 5

Adding a HTTP Interceptor

To add an interceptor, create a new class using Angular CLI.

ng g class my-http-interceptor

And then import the following modules (HttpEvent, HttpInterceptor, HttpHandler, HttpRequest) from HTTPClientModule. Then create an interceptor method as follows:

import { Injectable, Injector } from '@angular/core';
import {
  HttpEvent,
  HttpInterceptor,
  HttpHandler,
  HttpRequest
} from '@angular/common/http';
import { Observable } from 'rxjs/Rx';
import 'rxjs/add/observable/throw';
import 'rxjs/add/operator/catch';

@Injectable()
export class MyHttpInterceptor implements HttpInterceptor {
  constructor() {}

  intercept(
    req: HttpRequest<any>,
    next: HttpHandler
  ): Observable<HttpEvent<any>> {
    console.log('intercepted request ... ');

    // Clone the request to add the new header.
    const authReq = req.clone({
      headers: req.headers.set('headerName', 'headerValue')
    });

    console.log('Sending request with new header now ...');

    //send the newly created request
    return next.handle(authReq).catch((error, caught) => {
      //intercept the respons error and displace it to the console
      console.log('Error Occurred');
      console.log(error);
      //return the error to the method that called it
      return Observable.throw(error);
    }) as any;
  }
}

Now you have an interceptor but it won’t work because the application doesn’t know it exists. Open the app.modules.ts and modify it to include the interceptor by: Importing the interceptor class from your class and import the HTTP_INTERCEPTORS from @angular/common/http as shown below.

import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http';
import { MyHttpInterceptor } from './httpinterceptor';

Then add a new HTTP_INTERCEPTOR provider to your app.modules.ts. This will enable your app to recognize and use the new interceptor. This should be added inside the @NgModules below the imports as illustrated below:

providers: [
  {
    provide: HTTP_INTERCEPTORS,
    useClass: MyHttpInterceptor,
    multi: true
  }
],

Your new app.modules.ts should look like this now:

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http';
import { MyHttpInterceptor } from './httpinterceptor';
import { AppComponent } from './app.component';

@NgModule({
  declarations: [AppComponent],
  imports: [BrowserModule, HttpClientModule],
  providers: [
    {
      provide: HTTP_INTERCEPTORS,
      useClass: MyHttpInterceptor,
      multi: true
    }
  ],
  bootstrap: [AppComponent]
})
export class AppModule {}

And the results will look as follows for a working interceptor:

Method 1 : No Error, Success Message is logged in console

When Method 2: It results to an error which is logged inside console

Any new http request you make from this project will all pass through the interceptor. You can find the whole source code of this project on Github here. Thank you.

Comments