No tienes acceso a esta clase

¡Continúa aprendiendo! Únete y comienza a potenciar tu carrera

Creando Data Transfers Objects

19/23
Recursos

NestJS utiliza el concepto de Objetos de Transferencia de Datos, o simplemente abreviado como DTO, para el tipado de datos y su segurización.

Qué son objetos de transferencia de datos o data transfers objects

Los DTO no son más que clases customizadas que tu mismo puedes crear para indicar la estructura que tendrán los objetos de entrada en una solicitud.

1. Creando DTO

Crea un nuevo archivo que por lo general lleva como extensión .dto.ts para indicar que se trata de un DTO.

// products.dto.ts
export class CreateProductDTO {
  readonly name: string;
  readonly description: string;
  readonly price: number;
  readonly image: string;
}

La palabra reservada readonly es propia de TypeScript y nos asegura que dichos datos no sean modificados.

Crea tantos atributos como tu clase CreateProductDTO necesite para dar de alta un nuevo producto.

2. Importando DTO

Importa la clase en tu controlador para tipar el Body del endpoint POST para la creación de un producto.

import { CreateProductDTO } from 'products.dto.ts';

@Post('product')
createProducto(@Body() body: CreateProductDTO): any {
    // ...
}

De esta forma, ya conoces la estructura de datos que tendrá el parámetro body previo a la creación de un producto.

SRC: DTOS

// src/dtos/products.dtos.ts
export class CreateProductDto {
  readonly name: string;
  readonly description: string;
  readonly price: number;
  readonly stock: number;
  readonly image: string;
}

export class UpdateProductDto {
  readonly name?: string;
  readonly description?: string;
  readonly price?: number;
  readonly stock?: number;
  readonly image?: string;
}
// src/controllers/products.controller.ts
export class ProductsController {
  @Post()
  create(@Body() payload: CreateProductDto) { // 👈 Dto
    ...
  }

  @Put(':id')
  update(
    @Param('id') id: string,
    @Body() payload: UpdateProductDto  // 👈 Dto
   ) { 
   ...
  }

}
// src/services/products.service.ts
export class ProductsService {
  create(payload: CreateProductDto) { // 👈 Dto
    ...
  }

  update(id: number, payload: UpdateProductDto) { // 👈 Dto
    ...	
  }

}

Contribución creada por: Kevin Fiorentino.

Aportes 26

Preguntas 19

Ordenar por:

¿Quieres ver más aportes, preguntas y respuestas de la comunidad?

La documentacion de Nest recomienda crear los DTOs con classes y no con interfaces.

  • Para que las validaciones sean tambien a nivel de ejecucion y no solo a nivel de desarrollo, podemos usar la lib interna de nest class-validator.
import { PartialType } from '@nestjs/mapped-types';
import { IsString, IsNumber, IsOptional, IsNotEmpty } from 'class-validator';

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

  @IsString()
  @IsOptional()
  description?: string;

  @IsNotEmpty()
  @IsNumber({ allowNaN: false })
  price: number;

  @IsNotEmpty()
  @IsNumber()
  readonly stock: number;

  @IsString()
  readonly image: string;
}


export class UpdateProductDto extends PartialType(CreateProductDto) {
  @IsOptional()
  @IsString()
  readonly name?: string;

  @IsString()
  @IsOptional()
  description?: string;

  @IsOptional()
  @IsNumber({ allowNaN: false })
  price?: number;

  @IsOptional()
  @IsNumber()
  readonly stock?: number;

  @IsOptional()
  @IsString()
  readonly image?: string;
}

readonly???
el signo ? para variables opcionales???

Se ve que Typescript si que promete

Funciones de los DTOs:

  • Proteger los datos
  • Validar y tipar datos
  • Evita hacer referencia a datos que no existan

Para no crear el IUpdateDto solo podrias utilizar algo como esto Partial<CreateProductDto>

Nico en tu método update de tu ProductsController haces una operación PUT pero en el ejemplo la operación no es de remplazo sino de actualización parcial, es decir un PATCH

dejo un articulo al respecto: https://rapidapi.com/blog/put-vs-patch/

Data Transfers Objects

Los data transfers object o DTO por sus siglas, es una guía para que el desarrollador y aquellos que consumen la API sepan que de forma espera tener el cuerpo de la solicitud.

No ejecuta ninguna validación de clases es mas una guía

Creación de un DTO

Creamos una carpeta dtos en el cual creamos nuestro archivo products.dto.ts aqui vamos a especificar que campos van a obtener el cuerpo de la solicitud:

export class CreateProductDto {
	readonly name: string;
	readonly description: string;
	readonly price: number;
	readonly stock: number;
	readonly imag: string;
}

Readonly: Indica que el campo no podrá ser editado.

Y luego lo importamos en nuestro controlador o services:

import { CreateProductDto } from './../../dtos/products.dto'
@Post()
  create(@Body() payload: CreateProductDto) {
    return this.productsService.create(payload);
  }

Entities vs DTOs

  • Entities may be part of a business domain. Thus, they can implement behavior and be applied to different use cases within the domain.
  • DTOs are used only to transfer data from one processor context to another. As such, they are without behavior - except for very basic and usually standardized storage and retrieval functions.

Fuente: https://www.linkedin.com/pulse/difference-between-entity-dto-what-use-instead-omar-ismail/?trk=pulse-article_more-articles_related-content-card

Yo los veo como schemas

Los Data Transfers Objects (DTO) nos permite tipar y validar los datos que provienen de la petición (body)

```ts import { Product } from 'src/entities/product.entity'; export type CreateProductDto = Readonly<Omit<Product, 'id'>>; export type UpdateProductDto = Readonly<Partial<CreateProductDto>>; ```

Estas son las grandes ventajas de TypeScript, en equipos grandes ayuda mucho porque ya sabes qué tipo de dato esperar y el IntelliSense te dice exactamente lo que necesitas saber 😎

Con tipos también funciona, y con partial convierto todos a valores opcionales:

export type ICreateProductDto = {
	readonly name: string;
	readonly description: string;
	readonly price: number;
	readonly stock: number;
	readonly image: string;
	readonly brand: string;
}

export type IUpdateProductDto = Partial<ICreateProductDto>;

Super interesante los DTOs, no conocia este concepto. Cuando trabajo con Angular, utilizo interfaces para tipar los payloads. Por ejemplo, en el caso del payload de productos yo haria lo siguiente:

export interface ProductRequest {
   name: string;
   description: string;
   stock: number:
   image: string;
}

funciona exactamente igual. Lo diferente, que me llamo la atencion es que con los DTOs puedes especificar que el atributo sea solo de lectura con readonly. Entonces esto da un mayor beneficio porque proteges mas los datos…muy interesante.

Definitivamente la única forma de aprender todo estos temas de configuración es poniéndolo en práctica en proyectos, pequeños, medianos o grandes.

Te falto definir el “Id” del producto en tu DTO, y el nombre de cada archivo DTO debe ser creado de manera “Singular”.

Es una obra maestra esto de los DTO

No estas usando métodos de la clase, así que puedes seguir usando interfaces con readonly, adicional yo suelo tener clases que tienen internamente un método que convierte a DTO (esto en el front), en Nest se podría implementar una interfaz DTO, que la clase lo reciba en el constructor y lo guarde en el formato que necesita

Crear el dto del UpdateProducts

Validar el @body y el servicio con el Data Transfer Objects (dtos) nos aseguramos que nos envien los datos en los tipos correctos

Implementar el Data Transfers Objects (dto) en el Controlador

readonly - solo lectura no es para manipular

Crear datos de transferencia de productos

Data Transfers Objects son objetos que nos permiten validar (tipar informacion) cuando se envían datos de transferencia

Pero al final TypeScript solo es experiencia de desarrollo

Los DTO no serian igual que los types en el frront?