Мне не удается правильно обрабатывать исключения в 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 в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
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

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