Encodera

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.

Оглавление

Исключения и фильтры исключений

В NestJS ошибку не отправляют вручную через объект ответа — её бросают как исключение. Встроенный обработчик ловит его и сам формирует JSON с кодом ответа. Фильтр исключений позволяет заменить этот обработчик своим, если нужен другой формат ошибок.

Встроенные исключения

Сейчас запрос несуществующей статьи возвращает пустой ответ с кодом 200. Правильный ответ — 404. Бросьте исключение в сервисе:

// src/posts/posts.service.ts
import { Injectable, NotFoundException } from '@nestjs/common';
import { Post } from './entities/post.entity';
 
@Injectable()
export class PostsService {
  private posts: Post[] = [];
 
  findOne(id: number): Post {
    const post = this.posts.find((item) => item.id === id);
 
    if (!post) {
      throw new NotFoundException(`Статья ${id} не найдена`);
    }
 
    return post;
  }
}

Откройте /posts/999 — придёт ответ с кодом 404:

{
  "message": "Статья 999 не найдена",
  "error": "Not Found",
  "statusCode": 404
}

Метод теперь всегда возвращает Post, а не Post | undefined, — проверять результат в контроллере не нужно.

ИсключениеКод
BadRequestException400
UnauthorizedException401
ForbiddenException403
NotFoundException404
ConflictException409
InternalServerErrorException500

Все они наследуют класс HttpException. Для редкого кода подойдёт он сам: throw new HttpException('Слишком много запросов', 429).

Фильтр исключений

Фильтр — класс, который ловит исключения и сам отправляет ответ. Пусть все ошибки блога содержат адрес запроса и время:

nest g filter common/filters/http-exception --flat
// src/common/filters/http-exception.filter.ts
import { ArgumentsHost, Catch, ExceptionFilter, HttpException } from '@nestjs/common';
import { Request, Response } from 'express';
 
@Catch(HttpException)
export class HttpExceptionFilter implements ExceptionFilter {
  catch(exception: HttpException, host: ArgumentsHost) {
    const http = host.switchToHttp();
    const request = http.getRequest<Request>();
    const response = http.getResponse<Response>();
    const status = exception.getStatus();
 
    response.status(status).json({
      statusCode: status,
      message: exception.message,
      path: request.url,
      timestamp: new Date().toISOString(),
    });
  }
}

@Catch(HttpException) говорит, какие исключения ловит фильтр. host.switchToHttp() даёт доступ к обычным объектам запроса и ответа Express.

Подключение фильтра

Для всего приложения — в src/main.ts:

// src/main.ts
import { HttpExceptionFilter } from './common/filters/http-exception.filter';
 
app.useGlobalFilters(new HttpExceptionFilter());

Для одного контроллера или метода — декоратором @UseFilters(HttpExceptionFilter). Снова откройте /posts/999: в ответе появятся поля path со значением /posts/999 и timestamp.

Частая ошибка

Если бросить обычную ошибку throw new Error('Статья не найдена'), NestJS не знает её кода и отвечает 500 с текстом Internal server error. Клиент не поймёт, что статьи просто нет. Для ожидаемых ситуаций всегда бросайте наследников HttpException, а 500 оставьте для настоящих сбоев.

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.