UnprocessableEntityException при назначении DTO в качестве типа данных для тела запроса

Вопрос или проблема

Я создаю POST шлюз вот так:

@Controller('users')
@ApiTags('user')
export class UserController {
  constructor(private readonly userService: UserService) {}

  @Post('register')
  @ApiBody({ type: NewUserInputDto })
  registerUser(@Body() newUserInput: NewUserInputDto) {
    return this.userService.registerUser(newUserInput);
  }
}

Класс ‘NewUserInputDto’ выглядит так:

export class NewUserInputDto {

    @ApiProperty()
    fullName: string;

    @ApiProperty()
    phone: string;

    @ApiProperty()
    email: string;

    @ApiProperty()
    password: string;

    @ApiProperty()
    retypedPassword: string;
}

Когда я пытаюсь отправить запрос с телом, соответствующим DTO, я получаю эту ошибку (я изменил некоторые сообщения об исключениях, чтобы они были понятнее):

[Nest] 47901  - 09/23/2024, 10:49:05 AM   ERROR [HttpExceptionFilter] Объект:
[
  {
    "target": {
      "fullName": "string",
      "phone": "string",
      "email": "string",
      "password": "string",
      "retypedPassword": "string"
    },
    "value": "string",
    "property": "fullName",
    "constraints": {
      "whitelistValidation": "свойство fullName не должно существовать"
    }
  },
  {
    "target": {
      "fullName": "string",
      "phone": "string",
      "email": "string",
      "password": "string",
      "retypedPassword": "string"
    },
    "value": "string",
    "property": "phone",
    "constraints": {
      "whitelistValidation": "свойство phone не должно существовать"
    }
  },
  {
    "target": {
      "fullName": "string",
      "phone": "string",
      "email": "string",
      "password": "string",
      "retypedPassword": "string"
    },
    "value": "string",
    "property": "email",
    "constraints": {
      "whitelistValidation": "свойство email не должно существовать"
    }
  },
  {
    "target": {
      "fullName": "string",
      "phone": "string",
      "email": "string",
      "password": "string",
      "retypedPassword": "string"
    },
    "value": "string",
    "property": "password",
    "constraints": {
      "whitelistValidation": "свойство password не должно существовать"
    }
  },
  {
    "target": {
      "fullName": "string",
      "phone": "string",
      "email": "string",
      "password": "string",
      "retypedPassword": "string"
    },
    "value": "string",
    "property": "retypedPassword",
    "constraints": {
      "whitelistValidation": "свойство retypedPassword не должно существовать"
    }
  }
]

[Nest] 47901  - 09/23/2024, 10:49:05 AM   ERROR [HttpExceptionFilter] свойство fullName не должно существовать
UnprocessableEntityException: Исключение о невозможности обработки сущности
    at ValidationPipe.exceptionFactory (/home/long/vegeta/HealthyFoodApplication_BackEnd/src/main.ts:74:16)
    at ValidationPipe.transform (/home/long/vegeta/HealthyFoodApplication_BackEnd/node_modules/@nestjs/common/pipes/validation.pipe.js:72:30)
    at processTicksAndRejections (node:internal/process/task_queues:95:5)
    at resolveParamValue (/home/long/vegeta/HealthyFoodApplication_BackEnd/node_modules/@nestjs/core/router/router-execution-context.js:147:23)
    at async Promise.all (index 0)
    at pipesFn (/home/long/vegeta/HealthyFoodApplication_BackEnd/node_modules/@nestjs/core/router/router-execution-context.js:150:13)
    at /home/long/vegeta/HealthyFoodApplication_BackEnd/node_modules/@nestjs/core/router/router-execution-context.js:37:30
POST /api/v1/users/register 422 115 - 10.342 ms

В чем может быть проблема?

Я попробовал удалить ограничение типа данных (которое выглядит так registerUser(@Body() newUserInput)), и все работает нормально. Я также писал другие шлюзы аналогичным образом, и они работают без проблем.

Ответ или решение

Ошибка UnprocessableEntityException, с которой вы столкнулись, возникает при попытке валидации входящих данных, которые не соответствуют ожиданиям вашего DTO. В вашем случае проблема связана с настройками валидации, применяемыми к классам DTO в NestJS.

  1. Проверка DTO: Убедитесь, что ваш класс NewUserInputDto правильно настроен. В вашем коде все выглядит корректно с точки зрения определения DTO, но необходимо проверить, не пропущены ли аннотации, касающиеся валидации.

    Если вы еще не сделали этого, добавьте аннотации для валидации из библиотеки class-validator.

    Пример для вашего DTO:

    import { IsEmail, IsNotEmpty, IsPhoneNumber, IsString, MinLength } from 'class-validator';
    import { ApiProperty } from '@nestjs/swagger';
    
    export class NewUserInputDto {
       @ApiProperty()
       @IsString()
       @IsNotEmpty()
       fullName: string;
    
       @ApiProperty()
       @IsPhoneNumber(null) // На всякий случай, вы можете указать страну
       @IsNotEmpty()
       phone: string;
    
       @ApiProperty()
       @IsEmail()
       @IsNotEmpty()
       email: string;
    
       @ApiProperty()
       @IsString()
       @IsNotEmpty()
       @MinLength(6) // Минимальная длина пароля
       password: string;
    
       @ApiProperty()
       @IsString()
       @IsNotEmpty()
       @MinLength(6) // Минимальная длина повторного пароля
       retypedPassword: string;
    }
  2. Включение валидации: Убедитесь, что вы включили валидацию в вашем приложении NestJS. Обычно это делается в главном файле приложения (например, main.ts). Вот как это можно сделать:

    import { ValidationPipe } from '@nestjs/common';
    import { NestFactory } from '@nestjs/core';
    import { AppModule } from './app.module';
    
    async function bootstrap() {
       const app = await NestFactory.create(AppModule);
       app.useGlobalPipes(new ValidationPipe({ whitelist: true, forbidNonWhitelisted: true }));
       await app.listen(3000);
    }
    bootstrap();

    Параметры whitelist и forbidNonWhitelisted помогут Вам предотвратить отправку данных, не определённых в DTO, и будут работать на генерацию ошибок валидации, если клиент попытается отправить дополнительные поля.

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

    {
       "fullName": "Иван Иванов",
       "phone": "+79991234567",
       "email": "ivan@example.com",
       "password": "securePassword",
       "retypedPassword": "securePassword"
    }

Если вы выполните все вышеперечисленные шаги, то проблема с UnprocessableEntityException должна быть устранена. Если ошибка по-прежнему появляется, проверьте логи и данные запроса, чтобы убедиться, что они соответствуют ожидаемым типам данных.

Оцените материал
Добавить комментарий

Капча загружается...