Aprende a realizar validaciones con Nest Framework mediante ValidationPipe, que es un pipe que permite resumir y automatizar el flujo de validación de datos de entrada, apoyado en decoradores que introduciremos en las declaraciones de clases DTO.
En este artículo vamos a aprender a trabajar con un pipe disponible en Nest que nos permite realizar las validaciones de la entrada de datos en las aplicaciones. Se trata de ValidationPipe, el cual resulta especialmente sencillo y práctico de utilizar.
ValidationPipe funciona como otros pipes de Nest, estableciendo toda una serie de comprobaciones que se realizarán antes que se ejecute el cuerpo de un método de un controlador. El método donde usaremos ValidationPipe implementa la ruta de una solicitud de Nest y solamente se ejecutará si todas las validaciones han sido correctas.
Además, Nest se encargará de generar los mensajes de error de una manera adecuada para los clientes, enviando los correspondientes status code en las respuestas y los mensajes de error necesarios. Todo este funcionamiento ya fue descrito anteriormente, cuando hablamos de los pipes en Nest, por lo que no vamos a explicar mucho más sobre el flujo de ejecución de un pipe, sino que vamos a aprender a usar ValidationPipe directamente.
Configurar un pipe global
Existen diversas maneras de trabajar con ValidationPipe y quizás la más práctica consiste en establecer un pipe global, de modo que todas las rutas puedan beneficiarse del flujo de validaciones de manera automática.
Para ello, al iniciar la aplicación Nest, en la función bootstrap()
del archivo main.ts
, podemos configurar los pipes globales con un método del objeto app llamado useGlobalPipes()
, pasándole por parámetro el pipe que queremos configurar de manera global.
Simplemente tenemos que usar un código como este en la función bootstrap():
async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.useGlobalPipes(new ValidationPipe());
await app.listen(3000);
}
Por supuesto, tenemos que importar la declaración de la clase ValidationPipe
para que esto funcione.
import { ValidationPipe } from '@nestjs/common';
Instalar las reglas de validación
Las reglas de validación nos servirán para hacer comprobaciones diversas y estándar, como asegurar que algo sea un entero, una cadena un boleano o cosas más complejas.
La clase ValidationPipe
está incluida en el propio framework, sin embargo, no ocurre lo mismo con las reglas de validación, que las tenemos que instalar de manera independiente.
Lo hacemos mediante npm con el comando:
npm i class-validator class-transformer
Ambos packages son necesarios para las aplicaciones, tanto class-validator, que tiene reglas de validación como class-transformer que permite realizar transformaciones en los datos.
Configurar las reglas mediante anotaciones en el DTO
Ahora vamos a indicarle a Nest qué reglas de validación se deben aplicar a cada dato que se reciba mediante solicitudes a la aplicación. Esto lo vamos a realizar dentro de las clases del DTO.
Recuerda que en un artículo anterior pudimos aprender qué era un DTO y construimos una clase para definir el DTO de un producto. Si no lo has leído todavía accede al artículo DTOs en Nest.
Ahora, en el archivo del DTO que habíamos creado, llamado product.dto.ts
, vamos a aplicar las reglas de validación para cada campo con anotaciones. Todas las anotaciones las conseguimos gracias al package "class-validator" que acabamos de instalar, que tiene una lista enorme de decoradores como @IsString()
o @IsInt()
.
El código de nuestra clase DTO quedará más o menos así.
import { IsInt, IsString } from "class-validator";
export class ProductDto {
@IsString()
name: string;
@IsString()
description: string;
@IsInt()
stock: number;
}
El package "class-validator" contiene un número muy amplio de decoradores para aplicar reglas de validación distintas. Podemos ver los decoradores disponibles gracias a TypeScript y nuestro editor.
Con estos sencillos pasos ya hemos conseguido realizar las validaciones. No necesitas hacer nada más! Lo mejor de todo es que el propio framework se encargará de hacer automáticamente las validaciones y enviar correctamente los mensajes de error si las reglas definidas con los decoradores no se han cumplido.
Por supuesto, tenemos que asegurarnos de usar la clase DTO en el método donde queramos que las validaciones se ejecuten. Simplemente con tipar el parámetro con la clase DTO se producirán las comprobaciones.
@Post()
createProduct( @Body() productDto: ProductDto ) {
this.productsService.insert(productDto);
}
Cómo se devuelven los errores de validación
Nest es el encargado de generar los errores de validación de una manera consistente para los clientes que usen el API.
Si el DTO había definido que en el body de la solicitud se tenía que enviar un objeto con ciertas propiedades y no se han cumplido las validaciones, entonces informará con un error que podría parecerse a esto:
{
"statusCode": 400,
"message": [
"stock must be an integer number"
],
"error": "Bad Request"
}
Este error está indicando el status code 400 (bad request) y el mensaje de que "stock" debería ser un número entero.
Si hay más de un error la propiedad message indicará todos, mediante una cadena para cada error que encuentre, que meterá en las casillas del array.
{
"statusCode": 400,
"message": [
"description must be a string",
"stock must be an integer number"
],
"error": "Bad Request"
}
Este error está enviando un status code 400 y además está informando que faltaban por indicar dos datos en el JSON del body, el campo "description" y el campo "stock".
Por supuesto, el método del controlador no se llegará a ejecutar en el caso que las validaciones no se cumplan, como ya explicamos cuando se relató el flujo de trabajo de los pipes en Nest.
Conclusión
Con esto hemos aprendido a utilizar ValidationPipe de una manera muy simple y completamente automatizada, gracias a la configuración de un pipe global. Es la manera más cómoda de proceder.
Para poder definir las reglas de validaciones usamos decoradores en la clase DTO. Finalmente, tenemos que usar esa clase DTO para tipar el tipo de datos que nos viene en el body de la solicitud y que extraemos con @Body()
en la firma del controlador.
Miguel Angel Alvarez
Fundador de DesarrolloWeb.com y la plataforma de formación online EscuelaIT. Com...