Cuando trabajamos con datos de solicitudes en Angular hacia una API externa, a veces necesitamos agregar o enviar encabezados. La idea de repetir el código en cada solicitud no es algo de lo que sentirse orgulloso.

Por ejemplo, cuando se trabaja con la API "ball don't lie", se requiere enviar el encabezado Authorization con la clave de la API. Una solución simple es crear un objeto con mis encabezados:

private _ballDontLieAuthHeader = {
          Authorization: `MI_ASOMBROSO_TOKEN`,
  }

Luego, agregue el encabezado _ballDontLieAuthHeader a cada solicitud. El código se ve así:

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: `MI_ASOMBROSO_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) {
        ...
  }
}

Tal vez funcione, pero ¿qué pasa si los encabezados son necesarios en otros servicios? Tendría que importar el _ballDontLieAuthHeader en todas partes, y cada método de solicitud necesitaría agregarlos 😿.

Una mejor alternativa es usar interceptores para esto. Vamos a explorar cómo hacerlo.

Los Interceptores

Los interceptores funcionales son funciones que se ejecutan en cada solicitud. Nos ayudan a agregar encabezados, reintentar solicitudes fallidas, almacenar en caché las respuestas, y hacer más.

Crear un interceptor es simple. Es solo una función con HttpRequest como parámetro y next para procesar el siguiente paso en la cadena de interceptores.

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

Los interceptores deben registrarse con el provideHttpClient(), por ejemplo, en el app.config o bootstrapApplication.

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

Ahora que sabemos lo fácil que es crear un interceptor, vamos a actualizar nuestro código moviendo la URL y la clave de la API al archivo de entorno. Luego, podemos crear y registrar el interceptor.

Configurar Los Entornos

Primero, a partir de Angular 15 o 16, los archivos de entorno no están incluidos por defecto. Sin embargo, podemos generarlos fácilmente usando el CLI de Angular. Ejecuta el comando ng g environments en la terminal, lo que creará los archivos environment.ts y environment.development.ts.

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

Abre el environment.ts y agrega la URL de la API y el token:

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

¡El entorno está listo! Vamos a crear y registrar nuestro interceptor.

Crear y Registrar el Interceptor

Usando el CLI de Angular, crea un interceptor ejecutando el comando ng g interceptor interceptors/authorization.

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

Abre el archivo authorization.interceptor.ts. En la función authorizationInterceptor, obtenemos los parámetros req y next.

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

Clonamos la solicitud usando el método .clone() y establecemos las propiedades a cambiar en la nueva instancia en los HttpHeaders. Usa req.headers.set('Authorization', ${environment.token}) para agregar el encabezado Authorization a la solicitud, y usa next para incluir el cambio en la solicitud.

El código final se ve así:

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);
};
​

Finalmente, abre el archivo app.config e importa provideHttpClient. Luego, registra el authorizationInterceptor usando la función withInterceptors:

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

Guarda los cambios y ¡voilà! ¡Cada solicitud ahora incluye el encabezado Authorization con el token 🎉!