How To Add HTTP Headers to Requests with Functional Interceptors in Angular
Tags: javascript, angular, frontend
Published: 2024-06-09 15:29:21

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**](https://www.balldontlie.io/), it requires sending the `Authorization` header with the API key. One simple solution is to create an object with my headers:

```typescript
  private _ballDontLieAuthHeader = {
          Authorization: `MY_AMAZING_TOKEN`,
  }
```

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

```typescript
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**](https://angular.dev/guide/http/interceptors#intercepting-response-events).

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.

```typescript
      
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`.

```typescript
      
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.

```typescript
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`:

```typescript
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.

```typescript
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.

```typescript
​
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:

```typescript
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:

```typescript
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 🎉!