Menu
CoddyTech

Interceptors

Parte de la sección TypeScript y NestJS del Journey de Node.js de Coddy. Lección 23 de 24.

Quieres que cada respuesta indique cuánto tardó, sin tener que tocar cada controlador. Un interceptor envuelve al controlador: el código que se ejecuta antes de next.handle() se ejecuta antes, y el código que se ejecuta sobre lo que devuelve next.handle() se ejecuta después.

intercept(context: ExecutionContext, next: CallHandler) {
    console.log('before');
    return next.handle().pipe(
        tap(() => console.log('after')),
    );
}

next.handle() proporciona el resultado del controlador como un observable de RxJS, un valor que llega más tarde. .pipe(tap(...)) ejecuta una función cuando llega el valor, antes de que Nest lo envíe; este pipe no tiene nada que ver con las tuberías de validación de Nest. Los guards se ejecutan antes que cualquier interceptor, así que una solicitud que un guard rechaza nunca llega al interceptor. Devuelve el observable encadenado: Nest envía lo que contiene. context.switchToHttp().getResponse() proporciona res, cuyo setHeader añade una cabecera.

app.useGlobalInterceptors(...) aplica un interceptor a todas las rutas; @UseInterceptors(...), a un solo controlador.

challenge icon

Desafío

Fácil

«Ejecutar» vuelve a iniciar tu rastreador usando src/main.ts. Los archivos de práctica separados pueden permanecer en el árbol; este servidor no los inicia.

Los clientes y tu propio sistema de supervisión quieren saber cuánto tardó cada solicitud. Añade el encabezado de respuesta X-Response-Time a cada respuesta correcta, sin modificar ninguna ruta.

  1. Abre src/common/response-time.interceptor.ts. En el método intercept de ResponseTimeInterceptor, primero toma nota de la hora actual con Date.now(). El código al principio de intercept se ejecuta antes que el método de la ruta.
  2. Obtén el res de Express con context.switchToHttp().getResponse().
  3. next.handle() ejecuta el método de la ruta y devuelve su resultado como un observable de RxJS: un valor que llega más tarde. Sigue devolviéndolo, pero pásalo por tap, que ya está importado desde rxjs, usando el método .pipe() del observable. La función que le pasas a tap se ejecuta cuando llega el resultado, antes de que Nest lo envíe. En esa función, llama a res.setHeader para establecer X-Response-Time en los milisegundos transcurridos desde que tomaste nota de la hora, seguidos de ms, como en 3ms. (El método .pipe() de RxJS no tiene nada que ver con las tuberías de validación del capítulo 3. Añade un paso a la cadena del observable.)
  4. En src/main.ts, registra el interceptor para toda la aplicación con app.useGlobalInterceptors(...), pasando una nueva instancia de ResponseTimeInterceptor, junto a la tubería y el filtro.
  5. Los cuerpos de las respuestas no deben cambiar. GET /tasks sigue devolviendo { "items": [...], "page": 1, "total": 3, "pages": 2 }.

Pruébalo: envía GET /tasks y abre la pestaña Headers de la respuesta. Verás X-Response-Time con un valor como 0ms o 2ms. También aparece en GET /stats, y en un POST de { "title": "Buy milk" } enviado con el encabezado x-api-key: tasks-key-123. Después, envía ese POST sin la clave: 403 y sin X-Response-Time. Nest ejecuta los guardias antes que los interceptores, así que el guardia rechazó la solicitud antes de que se iniciara tu interceptor. Un error lanzado dentro de una ruta también omite el encabezado, porque tap solo se ejecuta cuando llega un resultado.

Pruébalo tú mismo

import { CallHandler, ExecutionContext, Injectable, NestInterceptor } from '@nestjs/common';
import { Observable, tap } from 'rxjs';

@Injectable()
export class ResponseTimeInterceptor implements NestInterceptor {
    intercept(context: ExecutionContext, next: CallHandler): Observable<unknown> {
        // Registra la hora, deja que se ejecute el handler y luego establece X-Response-Time.
        return next.handle();
    }
}
quiz iconPonte a prueba

Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.

Todas las lecciones de TypeScript y NestJS

Practica por tu cuenta: Playground de Express