#Why can't I get a DTO property via getter?

13 messages · Page 1 of 1 (latest)

restive elm
#

I'm doing this just for study purposes and I had this doubt. I tested it by passing the DTO in a plainToClass and it works, but I wanted to understand why Nest doesn't work normally with pure DTO class.

I get this error below

[Nest] 409383  - 12/23/2024, 7:44:29 AM     LOG [RouterExplorer] Mapped {/users/:id, POST} route +2ms
[Nest] 409383  - 12/23/2024, 7:44:29 AM     LOG [NestApplication] Nest application successfully started +2ms
[Nest] 409383  - 12/23/2024, 7:44:35 AM   ERROR [ExceptionsHandler] createUserDto.getName is not a function
TypeError: createUserDto.getName is not a function
import { Injectable } from "@nestjs/common";
import { CreateUserDto } from "./dto/create-user.dto";

@Injectable()
export class UsersService {
  create(createUserDto: CreateUserDto) {
    console.log(createUserDto.getName());

    return {
      createUserDto,
      getterName: createUserDto.getName(),
    };
  }
}
import { IsNotEmpty, IsString } from "class-validator";

export class CreateUserDto {
  @IsString()
  @IsNotEmpty()
  private readonly name: string;

  public getName(): string {
    return this.name;
  }
}
oak jewel
#

What are you passing into UsersService.create? Can you show the controller and ValidationPipe configuration?

restive elm
#

It's not a serious application, I'm just doing tests, the controller is normal, I'm just passing the body inside just service, that's not the issue.

import { Controller, Post, Body, ValidationPipe } from "@nestjs/common";
import { UsersService } from "./users.service";
import { CreateUserDto } from "./dto/create-user.dto";

@Controller("users")
export class UsersController {
  constructor(private readonly usersService: UsersService) {}

  @Post()
  create(@Body(ValidationPipe) createUserDto: CreateUserDto) {
    return this.usersService.create(createUserDto);
  }
}
oak jewel
#

You need to inform the validation pipe to return the transformed instance. Use new ValidationPipe({transform: true}) and it should work as expected

oak jewel
#

Don't see why that would be the case

restive elm
#

Thanks for your help!

#

One more question, if you can answer, the property {"etc": "adw"} is not part of the dto, only the "name" is, but even so the dto processes it and returns it, this would already be a JS problem, right? Well, it is a fleeting "typing", both when you define the Param as number for example, and you try to pass a string like /users/awdaw, even though it is defined as number it still lets it pass, can you say anything about this?

For example, in SpringBoot, when you pass something different from what was defined in the DTO, it does not receive it, and if you pass a string instead of a number in the param IF the param was defined as number, it also does not pass and the application blocks.

oak jewel
#

There are options in the validation pipe that you can check for this

restive elm
#
import {
  Controller,
  Post,
  Body,
  ValidationPipe,
  Param,
  ParseIntPipe,
} from "@nestjs/common";
import { UsersService } from "./users.service";
import { CreateUserDto } from "./dto/create-user.dto";

@Controller("users")
export class UsersController {
  constructor(private readonly usersService: UsersService) {}

  @Post()
  create(
    @Body(new ValidationPipe({ transform: true, whitelist: true }))
    createUserDto: CreateUserDto,
  ) {
    return this.usersService.create(createUserDto);
  }

  @Post(":id")
  update(
    @Param("id", ParseIntPipe) id: number,
    @Body(ValidationPipe) createUserDto: CreateUserDto,
  ) {
    return this.usersService.update(+id, createUserDto);
  }
}

With whitelist: true it starts to do what I want, but behind the scenes there is an extra validation, right? I wanted to understand if it is Nest that chose to be this way or if it is a "flaw" in js?

oak jewel
#

This is a limitation of Typescript/JavaScript, because that type doesn't exist directly at runtime

restive elm