Interceptores en Angular

Publicado el 17.12.2023 a las 21:37

Interceptores en Angular

  1. ¿Qué es un interceptor en Angular?

  2. Enviando un token en una petición HTTP sin interceptor

  3. Gestionando errores en nuestras peticiones HTTP

  4. Programando un interceptor en Angular

    • ¿Cómo se crea el interceptor?

    • ¿Cómo se registra un interceptor en una aplicación Angular?

    • Añadiendo el token en un interceptor de Angular

    • Capturando los errores HTTP en un interceptor con Angular

  5. Repositorio en GitHub

Logo de fjmduran

Interceptores en Angular

Cuando trabajamos con aplicaciones que requieren autenticación y autorización, es muy común enviar al backend en cada petición el token del cliente para que pueda comprobar que somos un cliente válido.


Este token lo podemos enviar como un header personalizado, como un Bearer token... como queramos, pero tendremos que enviarlo en todas las peticiones a nuestro backend.


Pero los interceptores no sólo sirven para añadir headers a nuestras peticiones HTTP, también los podemos usar para capturar errores de dichas peticiones y tratarlas en un sólo lugar del código.


Los interceptores nos ayudarán a mantener el diseño de código del DRY ("Don't Repeat Yourself") que no es más que intentar no repetir código.

De esa forma conseguiremos un código más claro, mantenible y eficiente.

¿Qué es un interceptor en Angular?

Un interceptor es una característica que te permite interceptar y manipular las solicitudes HTTP y las respuestas HTTP antes de que lleguen al backend o después de que regresen del mismo.


Es una parte fundamental del sistema de manejo de solicitudes HTTP en Angular y se utilizan para llevar a cabo tareas comunes, como agregar encabezados a las solicitudes, manejar errores de manera uniforme...


En Angular, un interceptor es una clase que implementa la interfaz HttpInterceptor.


Esta interfaz requiere que se implemente un método llamado intercept, que toma una solicitud HTTP y un objeto HttpHandler.


Dentro del método intercept, podemos realizar diversas acciones, como modificar la solicitud antes de enviarla al backend o procesar la respuesta antes de que llegue al código que hizo la solicitud original.

Enviando un token en una petición HTTP sin interceptor en Angular

Antes de explicarte cómo se programa un interceptor te mostraré cómo enviaríamos un token en una petición HTTP sin interceptor.


En este ejemplo enviaré el token como un encabezado personalizado de la solicitud HTTP.

const my_headers = new HttpHeaders({
  'my_token'='ASDFNLKJ'
})
    
return this.http.get(url_backend, {
  headers:my_headers,      
}).pipe(
  map( (resp)=> console.log(resp)))
}
      

Si nunca has usado los interceptores en Angular, lo primero que se vendrá a la cabeza para no repetir en cada petición HTTP añadir el token será crear un método y llamar a ese método en cada petición HTTP.


Si usas los interceptores te ahorrarás incluso el tener que añadir en cada petición HTTP dicho método, Angular lo hará por nosotros.

Gestionando errores en nuestras peticiones HTTP

Los interceptores no sólo los podremos usar para añadir características a nuestra petición HTTP, si no que también los podremos usar para gesetionar las respuestas de nuestro backend.


Tradicionalmente usamos el método catchError de RXJS (concretamente se importa de rxjs/operators) para gestionar el error de una petición HTTP en Angular.


Te dejaré un ejemplo donde uso el método catchError para capturar el error de la petición HTTP.

return this.http.get(url_backend)
  .pipe(
    map( (resp)=> console.log(resp))),
    catchError(err:HttpErrorResponse => {
        console.log('Error en petición HTTP')
        console.warn(err);

        //necesitamos obligatoriamente devolver un observable
        //en este caso devolveré el trowError de rxjs que es un objeto que se
        //importa de rxjs

        return throwErrorm
    })
    
      

Programando un interceptor en Angular

¿Cómo se añade un interceptor a una aplicación Angular?

En la práctica, un interceptor es un servicio, así que añadiremos un servicio con el nombre del interceptor que quieras.


En mi caso lo llamaré token_interceptor y lo incluiré dentro de la carpeta interceptors.

ng g s interceptors/token_interceptor

Para convertir el nuevo servicio en un intercpeto tengo que implementar la interfaz HttpInterceptor (importar de @angular/common/http).


Quedaría algo así:

import { HttpHandler, HttpInterceptor, HttpRequest } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs';

@Injectable({
  providedIn: 'root'
})
export class Token_interceptorService implements HttpInterceptor {

  constructor() { }

  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {   
    console.log('Petición interceptada')  ;
    return next.handle(req);
  }
}
      

Si te fijas, en el método intercept estoy devolviendo el objeto next y le paso como argumento la solicitud.


Esto lo que hará es que devolverá la petición sin hacerle nada, es decir, con este código todas la peticiones HTTP están pasando por el interceptor pero el interceptor no hace nada, lo que hace es dejar pasar la petición.

Eso sí, antes imprimo en consola que he pasado para cerciorarme de que todo funciona correctamente.


Si ejectuas el código anterior, en realidad la peticiones HTTP no pasarán por el interceptor, y eso es porque no lo hemos declarado como provider en el app.module.

¿Cómo se registra un interceptor en una aplicación Angular?

Para decirle a Angular que tiene un interceptor disponible abriremos el app.module.ts y declararemos el interceptor como un provider.

import { Token_interceptorService } from './interceptors/token_interceptor.service';
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';

import { AppComponent } from './app.component';
import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http'

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    HttpClientModule
  ],
  providers: [
    {
      👉provide: HTTP_INTERCEPTORS,
      👉useClass: Token_interceptorService,
      multi:true //con este campo le decimos que esté pendiente de todas las peticiones HTTP
    }
  ],
  bootstrap: [AppComponent]
})
export class AppModule { }
      

Añadiendo el token en un interceptor de Angular

La solicitud que nos llega al interceptor no podemos manipularla, es inmutable.


Lo que hay que hacer es clonarla y después trabajar con el clon de la solicitud.


No me enrollo, te muestro el código:

import { HttpHandler, HttpInterceptor, HttpRequest } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs';

@Injectable({
  providedIn: 'root'
})
export class Token_interceptorService implements HttpInterceptor {

  constructor() { }

  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {   
  
  const headers = new HttpHeaders({
    'my_token'='ASDFNLKJ'
  });

  const reqClone = req.clone({
    headers
  });
  
  return next.handle(reqClone);
  }
}
      

Capturando los errores HTTP en un interceptor con Angular

No me enrollo, te muestro el código:

import { HttpHandler, HttpInterceptor, HttpRequest } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs';

@Injectable({
  providedIn: 'root'
})
export class Token_interceptorService implements HttpInterceptor {

  constructor() { }

  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {   
  
  const headers = new HttpHeaders({
    'my_token'='ASDFNLKJ'
  });

  const reqClone = req.clone({
    headers
  });
  
    return next.handle(reqClone).pipe(
      catchError(this.manipulaError)
    );
  }

  manipulaError(error:HttpErrorResponse){
    console.log('Sucedió un error');
        console.warn(error);       
        return throwError('Error personalizado');
  }
}
      

Repositorio en GitHub

Te dejo mi repositorio de GitHub donde encontrarás el código para tu comodidad.


Hasta luego 🖖