Мне не удается правильно обрабатывать исключения в NestJs

Я пытаюсь изучить NestJs, создав CRUD API. Я создал свой контроллер, модуль, сервис и т.д.

И создал конечную точку get users/id. Все работало нормально, и я решил добавить немного безопасности. Я хочу проверить, не является ли идентификатор нулевым и является строкой. Если нет, я хочу создать исключение (неверный запрос) + console.info сообщение. Я также хочу проверить, существует ли пользователь, когда я ищу пользователя с хорошим if. если нет, сгенерируйте не найденное исключение.

Вот мой сервис:

async findOne(id: string): Promise<IUser | null> {
    if (id === null || typeof id !== 'string') {
      throw new BadRequestException('Id must be a string');
    }
    const user = await this.userModel.findById(id).exec();
    if (user === null) {
      throw new NotFoundException('No user found for this id');
    }
    return user;
  }

И контроллер:

@Get(':id')
  async find(@Param('id') id: string) {
    try {
      return await this.userService.findOne(id);
    } catch (error) {
      if (error instanceof BadRequestException) {
        throw new HttpException(
          {
            status: HttpStatus.FORBIDDEN,
            error: 'This is a custom message',
          },
          HttpStatus.FORBIDDEN,
          {
            cause: error,
          },
        );
      } else if (error instanceof NotFoundException) {
        throw new HttpException(
          {
            status: HttpStatus.NOT_FOUND,
            error: 'This is a custom not found message',
          },
          HttpStatus.NOT_FOUND,
          {
            cause: error,
          },
        );
      }
    }
  }

Проблема в том, что когда я пытаюсь получить запрос с помощью .../users/1111, я получаю ответ 200. И когда я пытаюсь с хорошим идентификатором (строкой), но без связанного пользователя, я также получаю ответ 200.

Я не понимаю, почему .. Не могли бы вы мне помочь? Я также хочу зарегистрировать сообщение.

А у вас есть советы? Правильный ли способ (стандартный + элегантный)?

Спасибо ребята ;)

Обновлено: Вот мой контроллер:

@Get(':id')
  async find(@Param('id') { id }: IdDto) {
    try {
      return await this.userService.findOne(id);
    } catch (error) {
      if (error instanceof NotFoundException) {
        return response.status(HttpStatus.NOT_FOUND);
      } else {
        return response.status(HttpStatus.BAD_REQUEST);
      }
    }
  }

Мой сервис:

async findOne(id: string): Promise<IUser | null> {
    const user = await this.userModel.findById(id).exec();
    if (user === null) {
      throw new NotFoundException('No user found for this id');
    }
    return user;
  }

Мой дто:

import { IsString, IsNotEmpty, IsMongoId } from 'class-validator';
import { Transform, Type } from 'class-transformer';
import { ObjectId } from 'mongodb';

export class IdDto {
  @IsMongoId()
  id: string;
}

И когда я ищу .../users/aaaa или /users/63ecf079c305ac977da87bcb (действительный идентификатор mongo) или ...users/1111, я получаю: { "Код статуса": 400, "сообщение": [ «id должен быть идентификатором mongodb» ], "ошибка": "Неверный запрос" }

И я не знаю почему...

Я действительно хочу проверить, действителен ли идентификатор + проверить, существует ли пользователь (если идентификатор действителен). Что я должен делать ?

Спасибо :)

Запуск PHP на IIS без использования программы установки веб-платформы
Запуск PHP на IIS без использования программы установки веб-платформы
Установщик веб-платформы, предлагаемый компанией Microsoft, перестанет работать 31 декабря 2022 года. Его закрытие привело к тому, что мы не можем...
Оптимизация React Context шаг за шагом в 4 примерах
Оптимизация React Context шаг за шагом в 4 примерах
При использовании компонентов React в сочетании с Context вы можете оптимизировать рендеринг, обернув ваш компонент React в React.memo сразу после...
Библиотека для работы с мороженым
Библиотека для работы с мороженым
Лично я попрощался с операторами print() в python. Без шуток.
Настройка шаблона Metronic с помощью Webpack и Gulp
Настройка шаблона Metronic с помощью Webpack и Gulp
Я пишу эту статью, чтобы поделиться тем, как настроить макет Metronic с помощью Sass, поскольку Metronic предоставляет так много документации, и они...
Уроки CSS 6
Уроки CSS 6
Здравствуйте дорогие читатели, я Ферди Сефа Дюзгюн, сегодня мы продолжим с вами уроки css. Сегодня мы снова продолжим с так называемых классов.
Что такое Css? Для чего он используется?
Что такое Css? Для чего он используется?
CSS, или "Каскадные таблицы стилей", - это язык стилей, используемый в веб-страницах. CSS является одним из основных инструментов веб-разработки...
0
0
63
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

В вашем коде вы проверяете, что идентификатор имеет строку типа, а не нуль. Технически любой параметр является строкой, поэтому даже 1111 становится "1111". Вы можете убедиться в этом, зарегистрировав это так console.info({ id }) (ожидаемый результат: { id: "1111" }).

Для проверки я бы посоветовал следовать документации по каналам проверки: Документация NestJS.

TLDR; Следующий код добавит глобальный канал для проверки полезной нагрузки. app.module.ts (скопировано из NestJS | Pipes)

import { Module } from '@nestjs/common';
import { APP_PIPE } from '@nestjs/core';

@Module({
  providers: [
    {
      provide: APP_PIPE,
      useClass: ValidationPipe,
    },
  ],
})
export class AppModule {}

Чтобы это работало, вам нужно установить class-validator и class-transformer, поэтому запустите:

npm i --save class-validator class-transformer

Затем объявите класс, который будет служить планом DTO (объект передачи данных), например:

import { IsString, IsNotEmpty } from 'class-validator';

export class IdDto {
  @IsNotEmpty()
  @IsString()
  id: string;
}

Затем в вашем контроллере используйте IdDto:

@Get(':id')
  async find(@Param() { id }: IdDto) {
    ...

Этого уже должно быть достаточно для базовой проверки. Более того, это преобразует полезную нагрузку в формат, который вы ожидаете (или завершится ошибкой и выдаст ошибку проверки). Это делается с помощью plainToClass метода, представленного class-transformer. Так что никаких сюрпризов с приведением типов в JavaScript вроде "1" + 1 = "11" не будет.

Если вам нужно отформатировать ваши исключения (или обогатить их дополнительными данными), вы можете использовать фильтры исключений. Об этом есть хорошая документация в официальной документации.

Надеюсь, это поможет!

Редактировать

Удалите блок try ... catch в вашем контроллере. Вот так:

@Get(':id')
  async find(@Param('id') id: string) {
      return await this.userService.findOne(id);
  }

В вашем текущем коде есть аварийный случай. Вы проверяете наличие ошибки instanceof NotFoundException или instanceof BadRequestException. Поэтому, если это будет экземпляр HttpException, для этого нет причин, поэтому ошибка перехватывается, и контроллер отправляет пустой ответ 200.

Но когда я это делаю, когда я пытаюсь использовать ..../users/aaa, я получаю сообщение об ошибке. И как я могу проверить, существует ли пользователь?

DonaPaulsen 20.02.2023 13:09

Если запрос к базе данных возвращает null, вам нужно бросить NotFoundException. У вас уже есть необходимая логика в методе user.service in findOne. Разве это не желаемое поведение? Какую проблему ты пытаешься решить?

Dmitrii Tkachenko 20.02.2023 13:41

Эй :) Во-первых, мне нужно проверить, действителен ли идентификатор (идентификатор mongo), когда мы используем конечную точку API users/... , идентификатор должен быть действительным. Кроме того, я также хочу проверить, возвращает ли запрос базы данных значение null, а затем выдать исключение NotFoundException. Но как на самом деле поймать это в моем контроллере?

DonaPaulsen 20.02.2023 13:56

Для проверки идентификатора вы можете использовать декоратор @IsMongoId(). Но зачем его ловить в контроллере? Разве не логично бросать 404 напрямую? Если вы выдаете ошибку в любом месте кода во время запроса, он будет правильно отправлен клиенту. Пожалуйста, взгляните на Страницу документации NestJS. TLDR; вам не нужно беспокоиться об ошибке, просто выбросьте и забудьте. Если вам нужно отформатировать ошибку, вы можете использовать ExceptionFilters

Dmitrii Tkachenko 20.02.2023 14:01

Посмотрите на мой другой вопрос для IsMongoId() stackoverflow.com/questions/75509265/… пожалуйста :) Потому что я хочу создавать разные исключения и добавлять собственное сообщение :) Но, например, я тестировал с хорошим идентификатором, но это не так. связан с пользователем, и у меня есть ошибка 0, просто статус 200..

DonaPaulsen 20.02.2023 14:06

Удалите блок try catch из контроллера. просто return await this.userService.findOne(id). Я думаю, вы получаете пустой ответ со статусом 200, верно? Если это так, это означает, что операторы if не совпадают. Вы можете проверить это, добавив условие else { throw new Error('Uncaught error') }.

Dmitrii Tkachenko 20.02.2023 15:46

Я не понимаю .. что мне делать с пользовательским сервисом и пользовательским контроллером + id dto?

DonaPaulsen 20.02.2023 16:18

Хорошо, я изменил свой контроллер, как вы сказали: @Get(':id') async find(@Param('id') { id }: IdDto) { return await this.userService.findOne(id); } и мой сервис: async findOne(id: string): Promise<IUser | null> { const user = await this.userModel.findById(id).exec(); if (user === null) { throw new NotFoundException('Пользователь для этого идентификатора не найден'); } вернуть пользователя; } но когда я пытаюсь использовать /63ecf079c305ac977da87bcb, я получаю "statusCode": 400, "message": ["id должен быть строкой"],

DonaPaulsen 21.02.2023 12:42

Судя по обновленному коду, я понятия не имею, откуда берется id must be a string. @IsMongoId выдает такую ​​ошибку: id must be a mongodb id значит это не то. Можете ли вы убедиться, что вы сохранили код и запускается код с последними изменениями? Самый простой способ сделать это — остановить сервер, удалить папку ./dist и запустить сервер.

Dmitrii Tkachenko 21.02.2023 13:55

Теперь он выдает «это должен быть идентификатор mongodb», но не понимаю, потому что на самом деле это действительный идентификатор mongo.

DonaPaulsen 21.02.2023 15:32

Извините, ошибся в ответе. Должно быть @Param() без id (код controller). Извини за это. Пожалуйста, попробуйте, должно быть решено сейчас

Dmitrii Tkachenko 21.02.2023 16:02

Другие вопросы по теме