Пошук уроків, статей та іншого контенту
Код, що виконується і до, і після методу контролера — логування, трансформація відповіді, кешування.
На відміну від Guard і Pipe, які виконуються лише до методу контролера, Interceptor обгортає виклик методу цілком — може виконати код і до нього (як Guard), і після того, як метод контролера вже повернув результат, включно зі зміною самого результату перед відправленням клієнту.
import { CallHandler, ExecutionContext, Injectable, NestInterceptor } from "@nestjs/common";
import { Observable } from "rxjs";
import { tap } from "rxjs/operators";
@Injectable()
export class LoggingInterceptor implements NestInterceptor {
intercept(context: ExecutionContext, next: CallHandler): Observable<unknown> {
const request = context.switchToHttp().getRequest();
const start = Date.now();
console.log(`Запит: ${request.method} ${request.url}`);
return next.handle().pipe(
tap(() => {
console.log(`Відповідь за ${Date.now() - start}мс`); // виконується ПІСЛЯ методу контролера
}),
);
}
}next.handle() — виклик самого методу контролера (і всього, що йде після Guard і Pipe); він повертає RxJS Observable, а не звичайний Promise — Interceptor може підписатись на результат через оператори RxJS (tap, map тощо), не заглиблюючись у бібліотеку RxJS повністю для базового використання.
Оператор map дозволяє змінити саму форму відповіді перед відправленням клієнту — типовий приклад: обгорнути всі відповіді застосунку в однаковий конверт формату:
@Injectable()
export class ResponseWrapperInterceptor implements NestInterceptor {
intercept(context: ExecutionContext, next: CallHandler) {
return next.handle().pipe(
map((data) => ({ success: true, data })), // { success: true, data: <результат контролера> }
);
}
}Так само, як Guard, Interceptor підключається декоратором @UseInterceptors() на метод, контролер чи глобально для всього застосунку через app.useGlobalInterceptors().
Практичне правило вибору між трьома механізмами: Guard — «чи можна обробляти цей запит узагалі», Pipe — «чи коректні вхідні дані цього конкретного параметра», Interceptor — «що зробити до і/або після виконання методу контролера, включно зі зміною самого результату».
Забути викликати next.handle() всередині intercept() — запит ніколи не дійде до методу контролера, і клієнт не отримає відповіді.
Класти логіку валідації вхідних даних в Interceptor замість Pipe — технічно можливо, але порушує усталений розподіл відповідальності між механізмами, ускладнюючи код для інших розробників команди.
Боятись RxJS-синтаксису й уникати Interceptors узагалі — для базових задач (логування, трансформація відповіді) достатньо кількох операторів (tap, map) без глибокого занурення в реактивне програмування.
Interceptor обгортає виклик методу контролера цілком — може виконати логіку і до, і після нього, включно з трансформацією самого результату через next.handle().pipe(...) з операторами RxJS. Типові застосування — логування часу відповіді, обгортання відповідей у стандартний формат, кешування результату. Підключається так само декларативно, як Guard, через @UseInterceptors().