How To Add HTTP Headers to Requests with Functional Interceptors in Angular

Using Functional Interceptors to Insert HTTP Headers in Angular

When we work with request data in Angular to an external API, sometimes we need to add or send headers. The idea of repeating the code in each request is not something to feel proud of.

For example, when working with the ball don't lie API, it requires sending the Authorization header with the API key. One simple solution is to create an object with my headers:

  private _ballDontLieAuthHeader = {
          Authorization: `MY_AMAZING_TOKEN`,
  }

Next, add the _ballDontLieAuthHeader header to every request. The code looks like this:

import { inject, Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { delay, map } from 'rxjs';
import { Player } from '../entities/player';
​
@Injectable({ providedIn: 'root' })
export class PlayersService {
  private _http = inject(HttpClient);
​
  private _ballDontLieAuthHeader = {
          Authorization: `MY_AMAZING_TOKEN`,
  }
​
  public getPlayers() {
    return this._http
      .get<{ data: Array<Player> }>(`/players`, {
        headers: this._ballDontLieAuthHeader,
      })
      .pipe(
        map((response) => response.data),
        delay(5000),
      );
  }
  public getPlayerById(id: string) {
  ....
  }

  public deletePlayer(id: string) {
        ...
  }
}
​
​

Maybe it works, but what happens if the headers are needed in other services? I would have to import the _ballDontLieAuthHeader everywhere, and every request method would need to add them 😿.

A better alternative is to use interceptors for this. Let's explore how to do that.

The Interceptors

The functional interceptors are functions that run on every request. They help us add headers, retry failed requests, cache responses, and do more.

Creating an interceptor is simple. It's just a function with HttpRequest as a parameter and next to process the next step in the interceptor chain.


export function monitorInterceptor(req: HttpRequest<unknown>, next: HttpHandlerFn): Observable<HttpEvent<unknown>> {
  console.log(`🐒 hi!`);
  return next(req);
}
​

The interceptors must be registered with the provideHttpClient(), for example, in the app.config or bootstrapApplication.


bootstrapApplication(AppComponent, {providers: [
  provideHttpClient(
    withInterceptors([monitorInterceptor,myotherInterceptor]),
  )
]});

Now that we know how easy it is to create an interceptor, let's update our code by moving the API URL and key to the environment file. Then, we can create and register the interceptor.

Configure The Environments

First, starting with Angular 15 or 16, the environment files are not included by default. However, we can easily generate them using the Angular CLI. Run the command ng g environments in the terminal, which will create environment.ts and environment.development.ts files.

ng g environments
CREATE src/environments/environment.ts (31 bytes)
CREATE src/environments/environment.development.ts (31 bytes)

Open the environment.ts and add the API URL and token:

export const environment = {
  production: true,
  apiUrl: 'https://api.github.com/repos',
  token: 'your-api-key'
};
​

The environment is ready! Let's create and register our interceptor.

Create and Register Interceptor

Using the Angular CLI, create an interceptor by running the ng g interceptor interceptors/authorization command.

ng g interceptor interceptors/authorization
CREATE src/app/interceptors/authorization.interceptor.spec.ts (512 bytes)
CREATE src/app/interceptors/authorization.interceptor.ts (158 bytes)
​

Open the authorization.interceptor.ts file. In the authorizationInterceptor function, we get the req and next parameters.

export const authorizationInterceptor: HttpInterceptorFn = (req, next) => {
  return next(req);
};

We clone the request using the .clone() method and set the properties to change in the new instance in the HttpHeaders. Use req.headers.set('Authorization', ${environment.token}) to add the Authorization header to the request, and use next to include the change in the request.

The final code looks like this:

import { HttpInterceptorFn } from '@angular/common/http';
import {environment} from "../../environments/environment";
​
export const authorizationInterceptor: HttpInterceptorFn = (req, next) => {
  const requestWithAuthorization = req.clone({
    headers: req.headers.set('Authorization', `${environment.token}`),
  });
  return next(requestWithAuthorization);
};
​

Finally, open the app.config file and import provideHttpClient. Then, register the authorizationInterceptor using the withInterceptors function:

import { provideHttpClient, withInterceptors } from '@angular/common/http';
​
export const appConfig = {
  providers: [
provideHttpClient(withInterceptors([authorizationInterceptor])),
      ]
}

Save the changes and voilà! Every request now includes the Authorization header with the token 🎉!