El DTO (Data Transfer Object) es el objeto que se transfiere entre dos sistemas, en este caso el frontend y el backend. En aplicaciones web, es un JSON que se transfiere entre estos dos sistemas para realizar las operaciones que necesiten. Veamos como se trabaja con el desde Nest.
En primer lugar, lo recomendable por el sistema de archivos de Nest es crear una carpeta dto dentro de la carpeta del módulo. Dentro de la carpeta voy a crear el dto para la función que quiera tipar. Los DTOS sirven para poder tipar los objetos que vamos a recibir y que coincidan. Por ejemplo, si quiero tipar la funcion que crea las tareas debería crear un create-task.dto.ts
El DTO es una clase o una interfaz que contiene la estructura de lo que voy a recibir
export interface createTaskDto {
task: string;
status: boolean;
}
El DTO no va a impedir que se ejecute una request si, por ejemplo, falta alguno de los datos. Esto es porque TypeScript trabaja en tiempo de compilación y no en tiempo de ejecución. Para lo que si sirven los DTO es para hacer validaciones.
Las validaciones consisten justamente en chequear que la data que se envia desde el cliente sea la que esperamos, para esto si son obligatorios los DTO y de hecho es la funcion principal de los mismos en Nest. Para poder realizar validaciones en Nest es necesario instalar class-validator y class-transformer
pnpm i class-validator class-transformer -D
Una vez que lo tenes, creas las validaciones en tu DTO. Para hacerlo, necesitas crear tu DTO dentro de una clase y no dentro de una interfaz.
import { IsBoolean, IsString } from 'class-validator';
export class CreateTaskDto {
@IsString()
task: string;
@IsBoolean()
status: boolean;
}
Con esto, las validaciones ya están dentro del DTO. Ahora hay que llamarlo a traves de algo que Nest llama Pipes. Para eso nos vamos al controlador
@Post()
@UsePipes(new ValidationPipe())
createTask(@Body() task: CreateTaskDto) {
return this.taskService.createTask(task);
}
Vayamos por partes acá. Primero llamamos a UsePipes, un hook nativo de Nest. Este hook necesita crear un pipe de validación, que también es nativo de Nest. Con eso ya le damos a entender al servidor que antes de ir a createTask debe ejecutar la validación. Ahora vayamos a Postman y pasemosle un string al status en lugar de un booleano
Como podes ver, nos aparece el error de que el status deberia ser un booleano. Eso lo hizo automaticamente el Validation Pipe gracias a la configuracion del DTO.
Podes agregar en el DTO las validaciones que quieras, como por ejemplo el tamaño del texto, si un numero se encuentra dentro de un rango o hasta si es un numero de pasaporte. Podés chequear todas las posibilidades de verificación acá
Por cada accion que quieras validar tenes que importar el UsePipe. Sin embargo, podes importarlo una sola vez en el main de tu aplicacion y listo
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { ValidationPipe } from '@nestjs/common';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
await app.listen(3000);
app.useGlobalPipes(new ValidationPipe()); //acá
}
bootstrap();
Esto tiene una propiedad muy interesante. Supongamos que le llega un request que, junto con la tarea y el status, le manda una fecha. Nest la va a aceptar sin problemas. Si queremos evitar eso, podemos activar la propiedad whitelist
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { ValidationPipe } from '@nestjs/common';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
await app.listen(3000);
app.useGlobalPipes(new ValidationPipe({
whitelist:true
}));
}
bootstrap();