What Is Angular Interceptors & How To Use

What Is Angular Interceptors & How To Manage HTTP Requests and Error Handling

Angular has given tremendous features with every release of it. Some of the dominating features include support for Model-View pattern, special subjects like Async subject, Behaviour subject in Angular, etc.

What Is Angular Interceptors & How To Manage HTTP Requests and Error Handling 1

In this blog, we’ll learn about Angular Interceptors.

What is an Angular Interceptor?

Angular does support many kinds of service, Interceptor is one of them. Interceptors are a unique type of Angular service which can be implemented in our project.

What Is Angular Interceptors & How To Manage HTTP Requests and Error Handling 3
What Is Angular Interceptors

By using interceptor, we can intercept in incoming or outgoing HttpRequest or HttpRespond with httpClient. We can handle HTTP request at a global level with the help of Interceptor.

What is the meaning of intercepting HTTP requests/responses?

So far, we know that we can use an interceptor to intercept HTTP calls, but what’s the meaning of intercepting it?

By intercepting those HTTP requests/responses we can modify or update the values of that particular request.

We will be going to see three different interceptor implementations in this article:

  • Handling HTTP headers
  • HTTP response formatting
  • HTTP error handling

Let’s get started.

Let assume we had implemented basic API which will exactly look like this.

import { Injectable } from '@angular/core';
import { HttpInterceptor, HttpEvent, HttpResponse, HttpRequest,
 HttpHandler } from '@angular/common/http';
import { Observable } from 'rxjs';
@Injectable()
export class MyInterceptor implements HttpInterceptor {
  intercept(httpRequest: HttpRequest<any>, next: HttpHandler): 
Observable<HttpEvent<any>> 
{
    return next.handle(httpRequest);
  }
}

We will have to implement the HttpInterceptor interface from @angular/common/HTTP package to create an Interceptor. The intercept () method will be an automatic which can be use whenever our application makes an HTTP request using the HttpClient service.

Angular will pass a reference to the httpRequest object whenever the intercept () method is called. By using this request, we can view it and modify it as per our requirements.

Must Read-  5 Best File Sharing Applications You Should Know in 2021

Once we are done with our logic, we can call next. handle and we can return the modified request onto our application. Just for information, we can add multiple interceptors in our application.

After creating our interceptor, we will have to register it as a multi-provider so that we can use it in multiple ways.

NOTE: We must register the provider to the app. module to use it at a global level in our application, and also interceptor will only intercept the request which is made with the use of the HttpClient service.

App.module.ts

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { HttpClientModule, HTTP_INTERCEPTORS } from 
'@angular/common/http';
import { RouterModule, Routes } from '@angular/router';
import { TheInterceptor } from './the.interceptor';
import { AppComponent } from './app.component';
@NgModule({
  imports: [BrowserModule, HttpClientModule],
  declarations: [AppComponent],
  bootstrap: [AppComponent],
  providers: [
    { provide: HTTP_INTERCEPTORS, useClass: TheInterceptor, multi: true }
  ]
})
export class AppModule { }

This was the basic implementation, now let’s start with our first interceptor.

HTTP Header Interceptor:

As you know every time we have to return an API key to an authenticated API endpoint via a request Header. With the use of an interceptor, we can make this implementation automatically.

Let’s see how we can achieve that:

import { Injectable } from '@angular/core';
import { HttpInterceptor, HttpEvent, HttpResponse, HttpRequest, HttpHandler } from '@angular/common/http';
import { Observable } from 'rxjs';
import { map, filter } from 'rxjs/operators';
@Injectable()
export class HeaderInterceptor implements HttpInterceptor {
  intercept(httpRequest: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    const API_KEY = 'Ifour';
    return next.handle(httpRequest.clone({ setHeaders: { API_KEY } }));
  }}

We can call the same method to update/change the request object and return a new copy on the HttpRequest Object. As you can see we have attached the API_KEY value as a header to every HTTP request with httpRequest.clone({setHeaders: {API_KEY}});

Now let’s get HTTP request with the use of HttpClient.

import { Component, OnInit } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';
import { tap } from 'rxjs/operators';
@Component({
  selector: 'app-header',
  template: `
    <h2>Example Of Header</h2>
    <pre>{{ data | json }}</pre>
  `
})
export class HeaderComponent implements OnInit {
  data: {};
  constructor(private httpClient: HttpClient) { }
  ngOnInit() {
    this.httpClient.get('/assets/header.json').subscribe(data => this.data = data);
  }
}

Now you can see your API_KEY in your browser->inspect mode -> network->headers.

What Is Angular Interceptors & How To Manage HTTP Requests and Error Handling 5
Fig: Instruction for API_KEY

Now we don’t have to write that logic for the API key every time, this will work in our whole application.

Now we don’t have to write that logic for the API key every time, this will work in our whole application.

Must Read-  [Unconventional Guide] Browser Hijacking and Methods of Prevention

Formatting JSON format:

Sometimes we have to modify/change the request value which we got back from an API response.

Sometimes we have to work with APIs which return data in an ugly format which will make it difficult to work with. But we do a solution for that, interceptors.

We can format the response’s data or clean it up before it gets out of application logic. Let’s understand it with an example:

{
  "id": "ifour",
    "metadata": "*_*",
    "data": {
      "users": {
      "count": 5,
      "list": [
        "Jayraj",
        "Raj",
        "Lokesh"
      ]
    }
  }
}

As we can see, in this example our data is nested deeply within the response object. We can reformat it or clean up the data with the use of Interceptor.

import { Injectable } from '@angular/core';
import { HttpInterceptor, HttpEvent, HttpResponse, HttpRequest, HttpHandler } from '@angular/common/http';
import { Observable } from 'rxjs';
import { map, filter } from 'rxjs/operators';
@Injectable()
export class FormatInterceptor implements HttpInterceptor {
  intercept(httpRequest: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    return next.handle(httpRequest).pipe(
      filter(event => event instanceof HttpResponse && httpRequest.url.includes('format')),
      map((event: HttpResponse<any>) => event.clone({ body: event.body.data.users.list }))
    );
  }
}

We can determine if it is a request we want to ignore or change/modify by inspecting the URL with the use of the HttpRequest object. We can modify the request and response form API.

filter(event => event instanceof HttpResponse && httpRequest.url.includes('format')),

Now all things are done, we have filtered out the request we want, we can now update the response body to be a simple array of the user that we want to display.

return next.handle(httpRequest).pipe(
  filter(event => event instanceof HttpResponse && httpRequest.url.includes('format')),
  map((event: HttpResponse<any>) => event.clone({ body: event.body.data.users.list }))
);

In our component page, we can subscribe to our data without having to deal with the response object.

import { Component, OnInit } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';
@Component({
  selector: 'app-format',
  template: `
    <h2>Formated JSON</h2>
    <pre>{{ data | json }}</pre>
  `
})
export class FormatComponent implements OnInit {
  data: {};
  constructor(private httpClient: HttpClient) { }
  ngOnInit() {
    this.httpClient.get('/assets/format.json').subscribe(data => this.data = data);
  }
}

Error Handling:

Interceptors can also be used to handle HTTP errors. We can decide how we want to show error with the use of interceptor whether to show it as a log errors or show it in the UI.

import { Injectable } from '@angular/core';
import { HttpInterceptor, HttpEvent, HttpResponse, HttpRequest, HttpHandler, HttpErrorResponse } from '@angular/common/http';
import { Observable } from 'rxjs';
import { retry } from 'rxjs/operators';
@Injectable()
export class RetryInterceptor implements HttpInterceptor {
  intercept(httpRequest: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    return next.handle(httpRequest).pipe(retry(2));
  }
}

We can use the RxJs retry () operator in our request handler. We can retry failed observable streams that have thrown errors which can execute with the help of the retry operator.

Must Read-  Best 8 Tips to Stay Safe on Public Wi-Fi Networks

We can also send a re-request to our HTTP call because angular HTTP service uses observables which allow us to do that.

import { Component, OnInit } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable, of } from 'rxjs';
import { catchError } from 'rxjs/operators';
@Component({
  selector: 'app-retry',
  template: `<pre>{{ data | json }}</pre>`
})
export class RetryComponent implements OnInit {
  data: {};
  constructor(private httpClient: HttpClient) { }
  ngOnInit() {
    this.httpClient.get('https://example.com/404').pipe(
      catchError(err => of('there was an error')) // return a Observable with a error message to display
    ).subscribe(data => this.data = data);
  }
}

Conclusion

We can use an interceptor to add, replace, or remove request headers, like we have shown in this blog. We can define some global HTTP request value like API_KEY.

Suggested –

Similar Posts