47. DTO - Data Transfer Object

DTO (Data Transfer Object) en NestJS: Validando Datos Antes de Llegar a la Base de Datos

En el desarrollo de APIs con NestJS, una de las mejores prácticas para manejar y validar datos es el uso de DTOs (Data Transfer Objects). Estos objetos nos permiten definir la estructura de los datos que fluyen entre diferentes partes de nuestra aplicación, asegurando consistencia y validación antes de que la información llegue a la base de datos.

¿Qué es un DTO?

Un DTO (Data Transfer Object) es un patrón de diseño que representa cómo se transfieren los datos entre diferentes capas de la aplicación. En NestJS, generalmente se implementa como una clase TypeScript que define la estructura esperada de los datos.

Ventajas de usar DTOs:

✅ Validación de datos: Asegura que los datos cumplan con un formato específico.
✅ Documentación implícita: La estructura del DTO sirve como documentación de los campos esperados.
✅ Seguridad: Evita que se envíen propiedades no deseadas.
✅ Mantenibilidad: Facilita cambios futuros en la estructura de los datos.


Ejemplo Práctico: DTO para Crear un Automóvil

Estructura del Proyecto

plaintext
Copy
Download
src/
│
├── cars/
│   ├── dto/
│   │   ├── create-car.dto.ts
│   │   └── update-car.dto.ts
│   ├── interfaces/
│   │   └── car.interface.ts
│   ├── cars.controller.ts
│   ├── cars.module.ts
│   ├── cars.service.ts
│   └── constants/
│       └── car.constants.ts
│
├── common/
│   ├── pipes/
│   │   └── validation.pipe.ts
│   └── filters/
│       └── http-exception.filter.ts
│
├── app.module.ts
├── app.controller.ts
├── app.service.ts
└── main.ts

1. Creando el DTO (create-car.dto.ts)

Definimos la estructura esperada para crear un automóvil:

typescript
Copy
Download
export class CreateCarDto {
  readonly brand: string;
  readonly model: string;
}
  • Usamos readonly para evitar modificaciones accidentales.

  • Solo aceptamos brand y model (ningún otro campo será válido).


Comparación: Controlador SIN DTO vs CON DTO

1. Versión SIN DTO (Problemas de estructura)

typescript
Copy
Download
import { Controller, Post, Body } from '@nestjs/common';

@Controller('cars')
export class CarsController {
  
  @Post()
  createCar(@Body() body: any) {  // ❌ 'any' permite cualquier dato
    return body;
  }
}

Problemas:

  • No hay validación de estructura.

  • Cualquier campo puede llegar (incluso mal escritos como Brand en vez de brand).

  • Riesgo de errores al interactuar con la base de datos.


2. Actualizando el Controlador (cars.controller.ts)

Modificamos el método POST para usar el DTO:

typescript
Copy
Download
import { Controller, Get, Post, Body } from '@nestjs/common';
import { CreateCarDto } from './dto/create-car.dto';

@Controller('cars')
export class CarsController {
  
  @Post()
  createCar(@Body() createCarDto: CreateCarDto) {
    return createCarDto;
  }
}
  • Ahora, @Body() espera un objeto que cumpla con la estructura de CreateCarDto.


3. Problema Actual: Falta Validación

Si probamos en Postman, aún podemos enviar datos incorrectos:

json
Copy
Download
{
  "Brand": "Toyota",  // ❌ Mayúscula incorrecta
  "Model": "Corolla", // ❌ Mayúscula incorrecta
  "extraField": 123   // ❌ Campo no permitido
}

Solución: Necesitamos validar los datos antes de procesarlos.


Próximos Pasos: Validación con Class Validator

En el siguiente post, veremos cómo integrar class-validator y class-transformer para:
✔ Validar que los campos sean correctos.
✔ Rechazar campos no definidos en el DTO.
✔ Mostrar mensajes de error claros.

Conclusión

Los DTOs son esenciales para mantener una API robusta y bien estructurada. Nos ayudan a:
🔹 Definir la estructura de datos esperada.
🔹 Evitar errores en la base de datos.
🔹 Mejorar la legibilidad del código.

En el próximo tutorial, implementaremos validaciones automáticas para garantizar que los datos sean correctos antes de procesarlos.

🚀 ¿Te gustaría aprender más sobre validación en NestJS? ¡Déjalo en los comentarios!

Comentarios

Entradas más populares de este blog

48. ValidationPipe - Class Validator y Class Transformer

32-Modulos

49. Pipes Globales - A nivel de Aplicación