Menu
CoddyTech

Interceptadores

Parte da seção TypeScript e NestJS do Journey de Node.js da Coddy. Lição 23 de 24.

Você quer que cada resposta informe quanto tempo levou, sem precisar mexer em cada handler. Um interceptor envolve o handler: o código antes de next.handle() é executado antes dele, e o código sobre o que next.handle() retorna é executado depois.

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

next.handle() fornece o resultado do handler como um observável do RxJS, um valor que chega mais tarde. .pipe(tap(...)) executa uma função quando o valor chega, antes de o Nest enviá-lo; esse pipe não tem nada a ver com os pipes de validação do Nest. Os guards são executados antes de qualquer interceptor, então uma solicitação recusada por um guard nunca chega até ele. Retorne o observável encadeado com pipe: o Nest envia o que ele carrega. context.switchToHttp().getResponse() fornece res, cujo setHeader adiciona um cabeçalho.

app.useGlobalInterceptors(...) aplica um interceptor a todas as rotas; @UseInterceptors(...), a um único controller.

challenge icon

Desafio

Fácil

Run inicia seu rastreador novamente, usando src/main.ts. Os arquivos de prática separados podem permanecer na árvore; este servidor não os inicia.

Os clientes e seu próprio monitoramento querem saber quanto tempo cada solicitação levou. Adicione um cabeçalho de resposta, X-Response-Time, a cada resposta bem-sucedida, sem mexer em nenhuma rota.

  1. Abra src/common/response-time.interceptor.ts. No método intercept de ResponseTimeInterceptor, primeiro registre o horário atual com Date.now(). O código no início de intercept é executado antes do método da rota.
  2. Obtenha o res do Express com context.switchToHttp().getResponse().
  3. next.handle() executa o método da rota e retorna o resultado como um observable do RxJS: um valor que chega depois. Continue retornando-o, mas passe-o por tap, que já está importado de rxjs, usando o método .pipe() do observable. A função que você passa para tap é executada quando o resultado chega, antes de o Nest enviá-lo. Nessa função, chame res.setHeader para definir X-Response-Time como o número de milissegundos desde que você registrou o horário, seguido de ms, como em 3ms. (O .pipe() do RxJS não tem relação com os pipes de validação do capítulo 3. Ele encadeia uma etapa ao observable.)
  4. Em src/main.ts, registre o interceptor para todo o app com app.useGlobalInterceptors(...), passando uma nova instância de ResponseTimeInterceptor, junto ao pipe e ao filtro.
  5. Os corpos das respostas não devem mudar. GET /tasks ainda retorna { "items": [...], "page": 1, "total": 3, "pages": 2 }.

Experimente: envie GET /tasks e abra a aba Headers da resposta. Você verá X-Response-Time com um valor como 0ms ou 2ms. GET /stats também o inclui, assim como uma solicitação POST de { "title": "Buy milk" } enviada com o cabeçalho x-api-key: tasks-key-123. Em seguida, envie esse POST sem a chave: 403, e sem X-Response-Time. O Nest executa os guards antes dos interceptors, então o guard recusou a solicitação antes de o interceptor começar. Um erro lançado dentro de uma rota também faz com que o cabeçalho seja omitido, porque tap só é executado quando um resultado chega.

Experimente você mesmo

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> {
        // Registre o horário, deixe o handler executar e, em seguida, defina X-Response-Time.
        return next.handle();
    }
}
quiz iconTeste seus conhecimentos

Esta lição inclui um quiz rápido. Comece a lição para respondê-lo e acompanhar seu progresso.

Todas as lições de TypeScript e NestJS

Pratique por conta própria: Playground de Express