Запропонувати правкуПокращити цю статтюДопрацюйте відповідь до «Що таке Exception Filter?». Ваші зміни проходять модерацію перед публікацією.Потрібне підтвердженняКонтентЩо ви змінюєте🇺🇸EN🇺🇦UAПереглядЗаголовок (UA)Коротка відповідь (UA)Exception Filter - клас, що перехоплює винятки, які виникають під час обробки запиту, і керує тим, яку відповідь отримає клієнт: реалізує інтерфейс `ExceptionFilter` з методом `catch(exception, host)`, позначається декоратором `@Catch()`, що вказує тип винятків для перехоплення. **Ключове:** Nest має вбудований фільтр для `HttpException` за замовчуванням, але власний фільтр (застосований локально через `@UseFilters()` чи глобально через `app.useGlobalFilters()`) потрібен, щоб уніфіковано форматувати нестандартні помилки (наприклад, від бази даних) у структурований JSON.Показується над повною відповіддю для швидкого нагадування.Відповідь (UA)Зображення## Що таке Exception Filter **Exception Filter** (фільтр винятків) - це **клас, який перехоплює помилки (exceptions)**, що виникають у процесі обробки запиту, і **керує тим, яку відповідь отримає клієнт**. > Якщо контролер чи сервіс кидає виняток (`throw new Error()` / `throw new HttpException()`), > фільтр може впіймати його, перетворити на читабельну відповідь і повернути клієнту структурований JSON. ## Приклад без фільтра ```javascript @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`) у зручну відповідь вигляду: ```javascript { "statusCode": 404, "message": "Користувача не знайдено", "error": "Not Found" } ``` Але якщо кинути **нестандартну помилку** (`throw new Error('Помилка БД')`), Nest не знає, як її оформити - і поверне 500 без форматування. Ось тут і знадобиться **Exception Filter**. ## Приклад кастомного Exception Filter ```javascript 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. Локально (на контролер чи метод): ```javascript @UseFilters(AllExceptionsFilter) @Controller('users') export class UsersController { @Get() findAll() { throw new Error('Щось пішло не так'); } } ``` ### 2. Глобально (на весь застосунок): ```javascript 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 буде впійманий фільтром**, і клієнт отримає акуратну, однакову відповідь. ## Приклад фільтра для конкретного типу помилок Можна перехоплювати **лише певні типи винятків**. ```javascript 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-запиту: ```javascript const ctx = host.switchToHttp(); const request = ctx.getRequest(); const response = ctx.getResponse(); ``` За його допомогою можна отримати доступ до: - запиту (`request`); - відповіді (`response`); - контексту виконання (`context`). ## Порядок роботи фільтрів 1. Контролер чи сервіс кидає виняток. 2. Nest намагається знайти відповідний Exception Filter. 3. Якщо фільтр знайдено → він обробляє помилку й формує відповідь. 4. Якщо ні → Nest використовує **вбудований фільтр** за замовчуванням. ## Часті застосування | Призначення | Приклад | |---|---| | Уніфікований формат помилок | Однакова JSON-відповідь для всіх винятків | | Обробка бізнес-помилок | "Недостатньо прав", "Акаунт заблоковано" | | Помилки БД | Перехоплення SQL/Prisma помилок і повернення дружнього повідомлення | | Різні контексти | Можна писати фільтри для WebSocket, GraphQL, RPC | ## Приклад: фільтр для Prisma ```javascript @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` | | Розширення | Можна писати власні для БД, авторизації, логування тощо |Для рев’юераПримітка для модератора (необов’язково)Бачить лише модератор. Прискорює рев’ю.