Photo by Gontran Isnard on Unsplash
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 🎉!