Better Http request with interceptors in Angular 8 and beyond

Ibrahima Ndaw - Nov 14 '19 - - Dev Community

Originally posted on my blog



Dealing with API based token is sometimes cumbersome. Due to the fact that, on every request, we have to send a token as parameter to be able to reach out the server.

In Angular, it becomes easier with the help of HttpClient interceptors. In this tutorial, I will lead on how to set up a token once and use it on every request with interceptors.

Prerequisite

Set up a new angular app

ng new my-app
Enter fullscreen mode Exit fullscreen mode

Then add a service file that will handle the logic of sending the request.

ng generate service data
Enter fullscreen mode Exit fullscreen mode

After successfully generated the service add the following lines to send the request to the server.

import { Injectable } from "@angular/core";
import { HttpClient, HttpParams } from "@angular/common/http";

@Injectable({
  providedIn: "root"
})
export class DataService {
  constructor(private http: HttpClient) {}

  getData() {
    return this.http.get("https://example.com/api/data", {
      params: new HttpParams().set(
        "auth-token",
        "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9"
      )
    });
  }

  getUsers() {
    return this.http.get("https://example.com/api/users", {
      params: new HttpParams().set(
        "auth-token",
        "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9"
      )
    });
  }
}

Enter fullscreen mode Exit fullscreen mode

And in your app.component.ts call the service we've created to achieve the request.

import { Component } from "@angular/core";

import { DataService } from "./data.service";

@Component({
  selector: "app-root",
  templateUrl: "./app.component.html",
  styleUrls: ["./app.component.scss"]
})
export class AppComponent {
  constructor(private dataService: DataService) {}

  showData() {
    this.dataService.getData().subscribe(response => {
      // Write your logic here to handle the data
      console.log(response);
    });
  }

  showUsers() {
    this.dataService.getUsers().subscribe(response => {
      // Write your logic here to handle the data
      console.log(response);
    });
  }
}
Enter fullscreen mode Exit fullscreen mode

As you can see in the data.sevice.ts file, we use the same params for both getData() and getUsers() methods to send the token.

Now it's time to optimize it with interceptors.

Interceptors

Http Interceptors were introduced with version 4.3 of Angular. They help a lot with handling request with the same parameters or headers.

To implement it, we need to create a new file auth.interceptor.ts. You can name it whatever you like, but it's a convention to add .interceptor to be clear about what's inside the class file. Next, add this following code block to the file.

import {
  HttpInterceptor,
  HttpRequest,
  HttpHandler,
  HttpEvent
} from "@angular/common/http";
import { Observable } from "rxjs";

export class AuthInterceptor implements HttpInterceptor {
  intercept(
    req: HttpRequest<any>,
    next: HttpHandler
  ): Observable<HttpEvent<any>> {
    const cloneReq = req.clone({
      params: req.params.set(
        "auth-token",
        "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9"
      )
    });
    return next.handle(cloneReq);
  }
}
Enter fullscreen mode Exit fullscreen mode

First, we need to import HttpInterceptor and implement it to our class to be able to access to the intercept() method. Then, we pass two arguments req and next to that method. The first is the request of type HttpRequest and can have any type of data, and the second next will handle the request and let it continue its journey.

The intercept() method is of type Observable and can receive any type of events.

The Http request is by default immutable, we can't edit it. Therefore, we need to create a copy by cloning the request with req.clone(). Now with this method, we can configure our params directly and return the cloneReq request and let it continue its way to the server.

Now, our interceptor will add the token as a parameter on every request before letting it reach out the server. We can even simplify our data.service.ts file by removing everything related to params.

import { Injectable } from "@angular/core";
import { HttpClient } from "@angular/common/http";

@Injectable({
  providedIn: "root"
})
export class DataService {
  constructor(private http: HttpClient) {}

  getData() {
    return this.http.get("https://example.com/api/data");
  }

  getUsers() {
    return this.http.get("https://example.com/api/users");
  }
}
Enter fullscreen mode Exit fullscreen mode

Conclusion

Http interceptors are useful on every matter. It's kind like middleware in back-end development. We can use it to modify our requests and also our responses.

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .