This page looks best with JavaScript enabled

6 Ways Of Using HTTP Interceptors In Angular

 ·  ☕ 11 min read  ·  ✍️ Adesh

What is Interceptor in Angular?

Angular Interceptor is a powerful feature that can be used in many ways for securing and handling many HTTP related phenomena. Interceptors provide a mechanism to intercept and/or mutate outgoing requests or incoming responses.

What is the use of Interceptors in Angular?

There is numerous use of interceptors in any Angular application. There are the following:-

  • Setting request headers in HTTP Calls using interceptors.
  • Authenticate HTTP calls by setting security tokens.
  • Change the response from the HTTP service call before it is used by the code block.
  • Use it for global error handling in your application.
  • Showing global spin loader or progress bar for each HTTP call.

Creating HTTP Interceptors in Angular

Now let’s learn various HTTP interceptor examples. We are going to learn different use-cases of interceptors in an angular app.

To implement an interceptor, you’ll want to create a class that’s injectable and that implements HttpInterceptor. The class should define an intercept method to correctly implement HttpInterceptor. The intercept method takes two arguments, req and next, and returns an observable of type HttpEvent.

  • req is the request object itself and is of type HttpRequest.
  • next is the HTTP handler, of type HttpHandler. The handler has a handle method that returns our desired HttpEvent observable.

1. Add Request Header using Interceptors

In this example, we will learn how to change the HTTP request header using the interceptor. Let’s create a new interceptor customheaderInterceptorclass in our project.

1
ng generate class customheaderInterceptor

Once you create interceptor class, import these dependencies in the same class file.

Put @Injectable() directive on customheaderInterceptor class. Now implement the class with HttpInterceptor. VS Code editor will a warning message to implement the HttpInterceptor. Click on the message and it will add an intercept method inside the class.

http interceptor in angular

Here is the code.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
import { Injectable } from "@angular/core";
import {
  HttpInterceptor,
  HttpHandler,
  HttpRequest,
  HttpEvent,
  HttpResponse,
} from "@angular/common/http";

@Injectable()
export class CustomHeaderInterceptor implements HttpInterceptor {
  intercept(
    req: HttpRequest<any>,
    next: HttpHandler
  ): import("rxjs").Observable<HttpEvent<any>> {
    throw new Error("Method not implemented.");
  }
}

HttpRequest: It is an outgoing HTTP request. It provides getters to fetch request properties such as methodurlWithParams etc.

HttpHandler: It transforms an HttpRequest into a stream of HttpEventHttpHandler provides handle() method to dispatch request from first interceptor to second and so on.

HttpResponse: It is a full HTTP response. It has getter methods such as bodyheadersstatusurl etc.

Configure HTTP Interceptors in AppModule

To use the same instance of HttpInterceptors for the entire app, import the HttpClientModule only in your AppModule, and add the interceptors to the root application injector. If you import HttpClientModule multiple times across different modules (for example, in lazy loading modules), each import creates a new copy of the HttpClientModule, which overwrites the interceptors provided in the root module.

Interceptors are configured in AppModule like below.

1
{ provide: HTTP_INTERCEPTORS, useClass: <Your Interceptor>, multi: true }

If there are multiple interceptors, you can create a constant and configure them in this constant.

1
2
3
4
5
export const httpInterceptorProviders = [
  { provide: HTTP_INTERCEPTORS, useClass: <Interceptor1>, multi: true }
  { provide: HTTP_INTERCEPTORS, useClass: <Interceptor2>, multi: true }
  { provide: HTTP_INTERCEPTORS, useClass: <Interceptor3>, multi: true }
];

Let’s see how to declare HTTP Interceptors in our AppModule file.

Import HTTP_INTERCEPTORS and CustomHeaderInterceptor in app.module.ts file. After importing, make an entry of HTTP_INTERCEPTORS in NgModule’s providers[] array.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
import { BrowserModule } from "@angular/platform-browser";
import { NgModule } from "@angular/core";

import { AppComponent } from "./app.component";
import { HTTP_INTERCEPTORS } from "@angular/common/http";
import { CustomHeaderInterceptor } from "../app/custom-header-interceptor";

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

Now, in order to change the HTTP request header, we need a mock service. Here, I am going to use an online mock service website mocky.io.

http interceptor angular

Here we got our service endpoint once you click on Generate my HTTP Response button.

http://www.mocky.io/v2/5e4605113300006700025eab

Let’s add a custom header in request via the interceptor.

1
2
req = req.clone({ headers: req.headers.set("custom-header", "ZeptoBook") });
return next.handle(req);

In this above code, we have added one header named custom-header and set its value to zeptobook. Now, for every ongoing HTTP request from our application, this custom-header will be appended in request headers.

Here is the complete code of our interceptor for changing the request header.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
import { Injectable } from "@angular/core";
import {
  HttpInterceptor,
  HttpHandler,
  HttpRequest,
  HttpEvent,
  HttpResponse,
} from "@angular/common/http";

@Injectable()
export class CustomHeaderInterceptor implements HttpInterceptor {
  intercept(
    req: HttpRequest<any>,
    next: HttpHandler
  ): import("rxjs").Observable<HttpEvent<any>> {
    req = req.clone({ headers: req.headers.set("custom-header", "ZeptoBook") });
    return next.handle(req);
  }
}

Finally, here is our HTTP call to mock service. This service call will have our custom header in the request header and it will return an HTTP response.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
import { Component, OnInit } from "@angular/core";
import { HttpClient } from "@angular/common/http";

@Component({
  selector: "app-root",
  templateUrl: "./app.component.html",
  styleUrls: ["./app.component.css"],
})
export class AppComponent implements OnInit {
  title = "interceptorapp";

  constructor(private http: HttpClient) {}

  ngOnInit() {
    this.http
      .get("http://www.mocky.io/v2/5e4605113300006700025eab")
      .subscribe((data) => {
        console.log(data);
      });
  }
}

Now you can verify your service request in the browser’s console window.

add custom header in http request in angular

Here is the service response.

http service response in angular

2. Cross-Site Request Forgery (XSRF or CSRF) protection by Interceptors

HTTP interceptors provide security from Cross-Site Request Forgery (XSRF or CSRF) by reading a token from cookie by, default XSRF-TOKEN, and sets it as an HTTP header, X-XSRF-TOKEN.

Cross-site request forgery, also known as one-click attack or session riding and abbreviated as CSRF (sometimes pronounced sea-surf) or XSRF, is a type of malicious exploit of a website where unauthorized commands are transmitted from a user that the web application trusts - wikipedia

By default, an interceptor sends this cookie on all mutating requests i.e. POST, PUT, DELETE etc. to relative URLs but NOT on GET / HEAD requests (since they are read-only) or on requests with an absolute URL (since it is a different domain altogether).

To take advantage of this, the server needs to set a token in a JS readable session cookie called XSRF-TOKEN on either the page load or the first GET request.

On subsequent requests, the server can verify that the cookie matches the X-XSRF-TOKEN HTTP header and thus, be sure that only code running on your domain has sent this request.

3. Global Error Handling using Interceptors

Using the interceptor, you can handle global errors that can happen across your application. Interceptors are the centralized system that takes care of your all HTTP requests and responses.

Since every request you’re making goes trough this interceptor, we can also use this interceptor to catch all requests that return as an instance of HttpErrorResponse. This is how you do that:

We send the request to the HttpHandler and then execute the request. In the callback function we check for errors. If the error is an instance of HttpErrorResponse we can send the request to an error handler that displays a nice little message with what went wrong.

In the below code, I changed my interceptor to catch an HTTP error for the wrong service URL. I have intentionally changed the service URL to the wrong URL and try to catch the error.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import { Injectable } from "@angular/core";
import {
  HttpInterceptor,
  HttpHandler,
  HttpRequest,
  HttpEvent,
  HttpResponse,
  HttpErrorResponse,
} from "@angular/common/http";
import { throwError } from "rxjs";
import { catchError } from "rxjs/operators";

@Injectable()
export class CustomHeaderInterceptor implements HttpInterceptor {
  intercept(
    req: HttpRequest<any>,
    next: HttpHandler
  ): import("rxjs").Observable<HttpEvent<any>> {
    return next.handle(req).pipe(
      catchError((error: HttpErrorResponse) => {
        if (error.status !== 401) {
          alert(error.message);
        }
        return throwError(error);
      })
    );
  }
}

I have put mocky.io to mocky1.io in my get() call in app.component.ts

http://www.mocky1.io/v2/5e4605113300006700025eab

1
2
3
4
5
6
7
  ngOnInit() {
    this.http
      .get("http://www.mocky1.io/v2/5e4605113300006700025eab")
      .subscribe(data => {
        console.log(data);
      });
  }

It will show an error alert on page load.

error handling using http interceptors

4. Using Angular Interceptors for Logging or Profiling

You can use the Angular interceptor for application logging purposes. We are now going to create a logger to show exactly which method is being called, the data being sent, headers and everything you need, there is no risk of mistaking one server interaction with another one.

The implementation below also includes a fix for GET calls using Internet Explorer, which sometimes seems to do some undesirable caching. By having this somewhat dirty code in an HTTP interceptor, we can at least keep it in one place and not have to think about it for every new HTTP GET call we add.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
import { Injectable } from "@angular/core";
import {
  HttpInterceptor,
  HttpHandler,
  HttpRequest,
  HttpEvent,
  HttpResponse,
  HttpErrorResponse,
} from "@angular/common/http";
import { throwError } from "rxjs";
import { catchError, tap } from "rxjs/operators";

@Injectable()
export class CustomHeaderInterceptor implements HttpInterceptor {
  intercept(
    req: HttpRequest<any>,
    next: HttpHandler
  ): import("rxjs").Observable<HttpEvent<any>> {
    if (req.method === "GET") {
      const time = new Date().getTime().toString();
      const dupReq = req.clone({
        params: req.params.set("nocache", time),
      });

      return next
        .handle(dupReq)
        .pipe(tap((httpEvent: HttpEvent<any>) => this.logResponse(httpEvent)));
    }
    return next
      .handle(req)
      .pipe(tap((httpEvent: HttpEvent<any>) => this.logResponse(httpEvent)));
  }

  private logResponse(httpEvent: HttpEvent<any>): void {
    if (httpEvent instanceof HttpResponse) {
      console.log("Interceptor Logging");
      console.log(httpEvent);
    }
  }
}

This logging interceptor now logs each GET request in the browser window.

angular interceptor for logging and profling

5. Mock Backend Using Angular Interceptors

There are times when we have to work fastly but server-side backend APIs are not ready to work. So, Angular provides you a facility to create your own mock backend service using the interceptor. It is very easy to create your own fake response data using the interceptor.

Let’s see how to create a mock backend using the interceptor.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
import { Injectable } from "@angular/core";
import {
  HttpInterceptor,
  HttpHandler,
  HttpRequest,
  HttpEvent,
  HttpResponse,
  HttpErrorResponse,
} from "@angular/common/http";
import { throwError, of } from "rxjs";
import { catchError, tap } from "rxjs/operators";

const mockData = {
  cars: [
    { name: "BMW", model: 2020 },
    { name: "Audi", model: 2019 },
  ],
};

@Injectable()
export class CustomHeaderInterceptor implements HttpInterceptor {
  intercept(
    req: HttpRequest<any>,
    next: HttpHandler
  ): import("rxjs").Observable<HttpEvent<any>> {
    if (req.method === "GET" && req.url === "http://localhost:4200/cars") {
      return of(new HttpResponse({ status: 200, body: mockData }));
    }
    next.handle(req);
  }
}

In the above code, we have created a mockData constant. From lines 26-28, we are checking the url and returning this mockData as an service response with a status code of 200.

In our app.component.ts file, we are calling our mock data service.

1
2
3
4
5
  ngOnInit() {
    this.http
      .get("http://localhost:4200/cars")
      .subscribe(data => console.log(data));
  }

Here is our response data from the mock backend service.

Mock Backend Using Angular Interceptor

6. Change Url by Interceptors

You can’t directly change HTTPRequest and HTTPResponse instance properties, because they are readonly and immutable.

They are immutable for a good reason: the app may retry a request several times before it succeeds, which means that the interceptor chain may re-process the same request multiple times. If an interceptor could modify the original request object, the re-tried operation would start from the modified request rather than the original. Immutability ensures that interceptors see the same request for each try. - As per Angular Docs

Since these are read-only, you can’t change url by using any string function like replace.

To alter the request, clone it first and modify the clone before passing it to next.handle(). You can clone and modify the request in a single step as in this example.

1
2
3
4
5
6
// clone request and replace 'http://' with 'https://' at the same time
const httpsReq = req.clone({
  url: req.url.replace("http://", "https://"),
});

return next.handle(httpsReq);

Summary

Interceptors were a great addition in Angular 4.3 and had many excellent use cases as we have seen here. As we’ve seen in these examples, interceptors provide a straightforward mechanism to interact with HTTP requests and responses. This makes it easy to add layers of control and provide more functionality throughout an application without duplicating logic.

Further Reading

Understanding Angular Modules and Its Types

How Change Detection Works In Angular

Testing Angular App With Karma And Jasmine

Best Chrome Extensions For Debugging Angular Apps

Share on

Adesh
WRITTEN BY
Adesh
Technical Architect