Що таке Exception Filter?
Що таке Exception Filter
Exception Filter (фільтр винятків) - це клас, який перехоплює помилки (exceptions), що виникають у процесі обробки запиту, і керує тим, яку відповідь отримає клієнт.
Якщо контролер чи сервіс кидає виняток (
throw new Error()/throw new HttpException()), фільтр може впіймати його, перетворити на читабельну відповідь і повернути клієнту структурований JSON.
Приклад без фільтра
@Controller('users')
export class UsersController {
@Get(':id')
findOne(@Param('id') id: string) {
if (id !== '1') {
throw new NotFoundException('Користувача не знайдено');
}
return { id: 1, name: 'John' };
}
}NestJS за замовчуванням загортає стандартні винятки (HttpException)
у зручну відповідь вигляду:
{
"statusCode": 404,
"message": "Користувача не знайдено",
"error": "Not Found"
}Але якщо кинути нестандартну помилку (throw new Error('Помилка БД')),
Nest не знає, як її оформити - і поверне 500 без форматування.
Ось тут і знадобиться Exception Filter.
Приклад кастомного Exception Filter
import {
ExceptionFilter,
Catch,
ArgumentsHost,
HttpException,
HttpStatus,
} from '@nestjs/common';
@Catch() // перехоплює УСІ помилки
export class AllExceptionsFilter implements ExceptionFilter {
catch(exception: unknown, host: ArgumentsHost) {
const ctx = host.switchToHttp();
const response = ctx.getResponse();
const request = ctx.getRequest();
const status =
exception instanceof HttpException
? exception.getStatus()
: HttpStatus.INTERNAL_SERVER_ERROR;
const message =
exception instanceof HttpException
? exception.getResponse()
: 'Internal server error';
response.status(status).json({
statusCode: status,
message,
path: request.url,
timestamp: new Date().toISOString(),
});
}
}Підключення Exception Filter
1. Локально (на контролер чи метод):
@UseFilters(AllExceptionsFilter)
@Controller('users')
export class UsersController {
@Get()
findAll() {
throw new Error('Щось пішло не так');
}
}2. Глобально (на весь застосунок):
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { AllExceptionsFilter } from './filters/all-exceptions.filter';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.useGlobalFilters(new AllExceptionsFilter());
await app.listen(3000);
}
bootstrap();Тепер будь-який кинутий Exception буде впійманий фільтром, і клієнт отримає акуратну, однакову відповідь.
Приклад фільтра для конкретного типу помилок
Можна перехоплювати лише певні типи винятків.
import { Catch, ExceptionFilter, ArgumentsHost, NotFoundException } from '@nestjs/common';
@Catch(NotFoundException)
export class NotFoundFilter implements ExceptionFilter {
catch(exception: NotFoundException, host: ArgumentsHost) {
const ctx = host.switchToHttp();
const response = ctx.getResponse();
response.status(404).json({
error: 'Ресурс не знайдено',
details: exception.message,
});
}
}Такий фільтр спрацює лише на throw new NotFoundException().
Що робить ArgumentsHost
ArgumentsHost - це універсальний об'єкт,
який дає доступ до контексту виконання: HTTP, WebSocket чи RPC.
Для HTTP-запиту:
const ctx = host.switchToHttp();
const request = ctx.getRequest();
const response = ctx.getResponse();За його допомогою можна отримати доступ до:
- запиту (
request); - відповіді (
response); - контексту виконання (
context).
Порядок роботи фільтрів
- Контролер чи сервіс кидає виняток.
- Nest намагається знайти відповідний Exception Filter.
- Якщо фільтр знайдено → він обробляє помилку й формує відповідь.
- Якщо ні → Nest використовує вбудований фільтр за замовчуванням.
Часті застосування
| Призначення | Приклад |
|---|---|
| Уніфікований формат помилок | Однакова JSON-відповідь для всіх винятків |
| Обробка бізнес-помилок | "Недостатньо прав", "Акаунт заблоковано" |
| Помилки БД | Перехоплення SQL/Prisma помилок і повернення дружнього повідомлення |
| Різні контексти | Можна писати фільтри для WebSocket, GraphQL, RPC |
Приклад: фільтр для Prisma
@Catch(Prisma.PrismaClientKnownRequestError)
export class PrismaExceptionFilter implements ExceptionFilter {
catch(exception: Prisma.PrismaClientKnownRequestError, host: ArgumentsHost) {
const ctx = host.switchToHttp();
const response = ctx.getResponse();
if (exception.code === 'P2002') {
response.status(409).json({
error: 'Conflict',
message: 'Duplicate entry',
});
} else {
response.status(500).json({
error: 'Database error',
message: exception.message,
});
}
}
}Підсумок
| Поняття | Опис |
|---|---|
| Exception Filter | Механізм для перехоплення й обробки винятків |
| Інтерфейс | ExceptionFilter з методом catch(exception, host) |
| Декоратор | @Catch() - вказує тип винятків |
| Застосування | Через @UseFilters() чи app.useGlobalFilters() |
| Мета | Централізована обробка помилок і форматування відповідей |
| За замовчуванням | Nest має вбудований фільтр для HttpException |
| Розширення | Можна писати власні для БД, авторизації, логування тощо |
Коротка відповідь
Для співбесідиКоротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.