Interceptores

<< Resource API Router de Angular >>

Los interceptores son un tipo de servicio que sirven para procesar de forma global las peticiones y respuestas a un servidor http. Es decir, podemos manipular tanto las peticiones, añadiendo datos, cabeceras, etc., como las respuestas del servidor. Desde la versión 15 de Angular, un interceptor puede ser una función del tipo HttpInterceptorFn. También se puede crear como una clase. Por defecto, Angular lo crea como función en las últimas versiones, a no ser que le pasemos la opción --functional false.

Ejemplo: Añadir la url base del servidor

Vamos a crear un interceptor para concatenar la url base del servidor a todas las peticiones http. De esta forma, si cambiara dicha url base, estaría centralizado ese cambio en un único sitio. Además, vamos a ver como diferenciar si estamos en un entorno de desarrollo o producción con la función isDevMode(). De esta manera podríamos apuntar a un servidor diferente mientras probamos la aplicación con ng serve, y al generar la versión de producción con ng build.

Primero crearemos el interceptor con el comando ng generate (o ng g).

ng g interceptor interceptors/base-url

Veremos que dentro del archivo base-url.interceptor.ts, se ha creado (y exportado) una función de tipo HttpInterceptorFn que recibe 2 parámetros:

  • req: HttpRequest → Esta es la solicitud antes de enviarla al servidor. Puedes modificar lo que envías clonando esta solicitud y estableciendo nuevos encabezados, etc.
  • next: HttpHandler → Si solo tienes un interceptor, este será el servicio de backend de Angular. Al llamarlo, pasarás la solicitud modificada (u original) a este servicio, que la enviará al servidor. Si tienes más interceptores, se le pasará la solicitud al siguiente interceptor en la lista.

Para indicarle a Angular que debe usar este interceptor, inclúyelo dentro de la función withInterceptors en un array de funciones interceptoras, que a su vez debe estar dentro de la función provideHttpClient en el archivo src/app.config.ts:

export const appConfig: ApplicationConfig = {
  providers: [
    // ...
    provideHttpClient(withInterceptors([baseUrlInterceptor])),
  ],
};

El interceptor clonará la petición (es un objeto inmutable) y le concatenará a la url de la misma, la url base del servidor, que puede ser diferente si estamos en desarrollo o producción. En el servicio ProductsService, ya no hará falta esa parte de la url:

import { HttpInterceptorFn } from '@angular/common/http';
import { isDevMode } from '@angular/core';

export const baseUrlInterceptor: HttpInterceptorFn = (req, next) => {
  const serverUrl = isDevMode() ? 'http://localhost:3000' : 'https://miservidor.com/api-products';
  const reqClone = req.clone({
    url: `${serverUrl}/${req.url}`,
  });
  return next(reqClone);
};

Ejemplo: Enviar token de autenticación

Un uso común para un interceptor en Angular es el de enviar las credenciales del usuario automáticamente. Para nuestro ejemplo enviaremos un token JWT que supuestamente habríamos almacenado durante el proceso de login. Crearemos un interceptor llamado auth que si detecta que tenemos un token de autenticación almacenado, lo enviará automáticamente en la cabecera Authorization con el prefijo Bearer.

ng g interceptor interceptors/auth

export const authInterceptor: HttpInterceptorFn = (req, next) => {
  const token = localStorage.getItem('token');

  if (token) { // Estamos autenticados
    const authReq = req.clone({
      headers: req.headers.set('Authorization', 'Bearer ' + token),
    });
    return next(authReq); // Petición con credenciales
  }
  return next(req); // Petición sin credenciales
};

En nuestro ejemplo de productos no tenemos autenticación, así que no vamos a hacer el ejemplo de hacer login a partir del correspondiente formulario. Básicamente sería guardar el token que nos devolviera el servidor cuando el login sea correcto con la clave token dentro de localStorage.

<< Resource API Router de Angular >>