<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>programacion &#8211; Jeff Santillán</title>
	<atom:link href="https://jeffsantillan.com/blog/tag/programacion/feed/" rel="self" type="application/rss+xml" />
	<link>https://jeffsantillan.com/blog</link>
	<description>Transformación Digital y Programación</description>
	<lastBuildDate>Fri, 19 Jun 2026 05:27:18 +0000</lastBuildDate>
	<language>es</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=7.1.4</generator>
	<item>
		<title>Nestjs uso de Validator y Transformers</title>
		<link>https://jeffsantillan.com/blog/nestjs-uso-de-validator-y-transformers/</link>
					<comments>https://jeffsantillan.com/blog/nestjs-uso-de-validator-y-transformers/#comments</comments>
		
		<dc:creator><![CDATA[Jefferson Santillan]]></dc:creator>
		<pubDate>Thu, 18 Jun 2026 23:28:07 +0000</pubDate>
				<category><![CDATA[Nestjs]]></category>
		<category><![CDATA[Programación]]></category>
		<category><![CDATA[REST API]]></category>
		<category><![CDATA[api]]></category>
		<category><![CDATA[nestjs]]></category>
		<category><![CDATA[programacion]]></category>
		<guid isPermaLink="false">https://jeffsantillan.com/blog/?p=283</guid>

					<description><![CDATA[Sin validaciones, un usuario puede enviar cualquier dato a tu API — un email inválido, una &#8230; <a title="Nestjs uso de Validator y Transformers" class="hm-read-more" href="https://jeffsantillan.com/blog/nestjs-uso-de-validator-y-transformers/"><span class="screen-reader-text">Nestjs uso de Validator y Transformers</span>Leer más</a>]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">Sin validaciones, un usuario puede enviar cualquier dato a tu API — un email inválido, una edad negativa, o campos vacíos — y llegarían directo a la base de datos. <code>class-validator</code> y <code>class-transformer</code> resuelven esto antes de que el request llegue al servicio</p>



<p class="wp-block-paragraph"><strong>Descripción</strong></p>



<p class="wp-block-paragraph"><em><strong><span style="text-decoration: underline;">class-transform </span></strong></em></p>



<p class="wp-block-paragraph">Se encarga de cambiar al tipo correcto de dato.</p>



<p class="wp-block-paragraph">En el servicio no se ven por que hacen su trabajo antes de que llegue el request ahí. El servicio recibe los datos ya validados y transformados.</p>



<p class="wp-block-paragraph">Donde actúan los transformers en el Param(&#8216;id&#8217;) del controlador.</p>



<pre class="wp-block-code has-small-font-size"><code>// Sin transform: true
@Get(':id')
findOne(@Param('id') id: string) {  // id llega como STRING "1"
  return this.usuarioService.findOne(+id); // necesitas el +id para convertir
}

// Con transform: true puedes hacer esto:
@Get(':id')
findOne(@Param('id', ParseIntPipe) id: number) { // id ya llega como NUMBER
  return this.usuarioService.findOne(id); // sin el +
}</code></pre>



<p class="wp-block-paragraph">El @body tambien convierte los tipos automaticamente</p>



<pre class="wp-block-code has-small-font-size"><code>// Si el DTO tiene edad: number
// y el cliente manda: { "edad": "25" }  ← string
// transform: true lo convierte a número automáticamente antes de llegar al servicio</code></pre>



<p class="wp-block-paragraph">Se coloco un transform explicito dentro del DTO create (CreateUsuarioDto)</p>



<pre class="wp-block-code has-medium-font-size"><code>@Type(() =&gt; Number)</code></pre>



<p class="wp-block-paragraph"><strong><em><span style="text-decoration: underline;">class-validator</span></em></strong></p>



<p class="wp-block-paragraph">Valida que los datos sean los correctos.</p>



<p class="wp-block-paragraph"><strong><em><span style="text-decoration: underline;">ValidationPipe</span></em></strong></p>



<p class="wp-block-paragraph">Se encarga de orquestar ambos.</p>



<p class="wp-block-paragraph">Vamos a utilizar el validator y transformers.</p>



<p class="wp-block-paragraph"></p>



<p class="wp-block-paragraph">Lo primero hay que instalar las dependencias.</p>



<pre class="wp-block-code has-small-font-size"><code>npm install class-validator class-transformer</code></pre>



<p class="wp-block-paragraph">voy a modificar el archivo principal main.ts importante los ValidationPipe y agregando unas lineas para su uso.</p>



<pre class="wp-block-code has-small-font-size"><code>import { ValidationPipe } from '@nestjs/common'; // Validator

  app.useGlobalPipes(new ValidationPipe({
    whitelist: true, // Elimina los campos que no estan en los DTOs
    forbidNonWhitelisted: true, // Lanza un error si llegan campos extra
    transform: true,  // Transforma tipos automaticamente.
  }));</code></pre>



<p class="wp-block-paragraph"><strong>Sin </strong>whitelist considera que el campo extra llega al servicio<br><strong>Con </strong>whitelist: true considera que campo extra se elimina silenciosamente<br><strong>Con </strong>forbidNonWhitelisted: true >> lanza error 400</p>



<p class="wp-block-paragraph">Quedando de esta manera.</p>



<pre class="wp-block-code has-small-font-size"><code>import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { ValidationPipe } from '@nestjs/common'; // Validator

async function bootstrap() {
  const app = await NestFactory.create(AppModule);

  app.useGlobalPipes(new ValidationPipe({
    whitelist: true, // Elimina los campos que no estan en los DTOs
    forbidNonWhitelisted: true, // Lanza un error si llegan campos extra
    transform: true,  // Transforma tipos automaticamente.
  }));

  await app.listen(process.env.PORT ?? 3000);
}
bootstrap();</code></pre>



<p class="wp-block-paragraph">He generado una entidad llamada Usuario para poder hacer las validaciones.</p>



<pre class="wp-block-code has-small-font-size"><code>nest g resource Usuario</code></pre>



<p class="wp-block-paragraph">Entonces vamos a utilizar arrays en memoria dado que no me he conectado a una base de datos prisma.</p>



<pre class="wp-block-code has-small-font-size"><code>// Usaremos arrays en memoria, dado que no conecte a prisma
export class Usuario {
    id!: number;
    nombre!: string;
    email!: string;
    edad!: number;
}</code></pre>



<p class="wp-block-paragraph">DTOs <strong>(Simple sin validaciones)</strong></p>



<pre class="wp-block-code has-small-font-size"><code>export class CreateUsuarioDto {
    nombre!: string;
    email!: string;
    edad!: number;    
}</code></pre>



<p class="wp-block-paragraph">Ahora le voy a incluir las validaciones en una primera version.</p>



<pre class="wp-block-code has-small-font-size"><code>import { IsEmail, IsNotEmpty, IsString, IsNumber, Min, Max } from 'class-validator';
<em>import { Type } from 'class-transformer';</em>

export class CreateUsuarioDto {

    @IsNotEmpty({message: 'El nombre es obligatorio'})
    @IsString()
    nombre!: string;

    @IsNotEmpty()
    @IsEmail({}, {message: 'Email inválido'})
    email!: string;

    @IsNumber()
    @Min(18, {message: 'Debe de ser mayor de 18'})
    @Max(99)
    @Type( () =&gt; Number) //Aqui se utiliza la clase transform explicitamente.
    edad!: number;
}</code></pre>



<pre class="wp-block-code has-small-font-size"><code>import { PartialType } from '@nestjs/mapped-types';
import { CreateUsuarioDto } from './create-usuario.dto';

export class UpdateUsuarioDto extends PartialType(CreateUsuarioDto) {}</code></pre>



<p class="wp-block-paragraph">Se define el servicio.</p>



<pre class="wp-block-code has-small-font-size"><code>import { Injectable, NotFoundException } from '@nestjs/common';
import { CreateUsuarioDto } from './dto/create-usuario.dto';
import { UpdateUsuarioDto } from './dto/update-usuario.dto';
import { Usuario } from './entities/usuario.entity'; // Importar entity

@Injectable()
export class UsuarioService {

  // Array en memoria como una base de datos temporal
  private usuarios: Usuario&#91;] = &#91;]
  private idCounter = 1;

  create(data: CreateUsuarioDto): Usuario {
    const usuario: Usuario = {
      id: this.idCounter++,
      ...data,
    };
    this.usuarios.push(usuario);
    return usuario;
  }

  findAll(): Usuario&#91;] {
    return this.usuarios;
  }

  findOne(id: number): Usuario {
    const usuario = this.usuarios.find(u =&gt; u.id === id);
    if (!usuario) throw new NotFoundException(`Usuario ${id} no encontrado`);
    return usuario;
  }

  update(id: number, data: UpdateUsuarioDto): Usuario {
    const usuario = this.findOne(id);
    Object.assign(usuario, data) // Actualiza solo los campos enviados
    return usuario;
  }

  remove(id: number): {message: string} {
    const index = this.usuarios.findIndex(u =&gt; u.id ===id);
    if (index === -1) throw new NotFoundException(`Usuario ${id} no encontrado`);
    this.usuarios.splice(index, 1);
    return {message: `Usuario ${id} eliminado`};
  }
  
}</code></pre>



<p class="wp-block-paragraph">En el controlador y el modulo, no hay mayor cambio.</p>



<p class="wp-block-paragraph">Formas de validar la operaciones CRUD de Usuario.</p>



<pre class="wp-block-code has-small-font-size"><code># Crear
Invoke-WebRequest -Uri http://localhost:3000/usuario -Method POST -Headers @{"Content-Type"="application/json"} -Body '{"nombre":"Jeff","email":"jeff@gmail.com","edad":25}' | Select-Object -ExpandProperty Content

# Listar
Invoke-WebRequest -Uri http://localhost:3000/usuario -Method GET | Select-Object -ExpandProperty Content | ConvertFrom-Json

# Actualizar
Invoke-WebRequest -Uri http://localhost:3000/usuario/1 -Method PATCH -Headers @{"Content-Type"="application/json"} -Body '{"nombre":"Jeff Santillan"}' | Select-Object -ExpandProperty Content

# Eliminar
Invoke-WebRequest -Uri http://localhost:3000/usuario/1 -Method DELETE | Select-Object -ExpandProperty Content</code></pre>



<p class="wp-block-paragraph"><strong>Validaciones</strong></p>



<p class="wp-block-paragraph">Error por ingreso de edad superior a 99</p>



<figure class="wp-block-image size-large"><img fetchpriority="high" decoding="async" width="1024" height="234" src="https://jeffsantillan.com/blog/wp-content/uploads/2026/06/image-44-1024x234.png" alt="" class="wp-image-286" srcset="https://jeffsantillan.com/blog/wp-content/uploads/2026/06/image-44-1024x234.png 1024w, https://jeffsantillan.com/blog/wp-content/uploads/2026/06/image-44-300x69.png 300w, https://jeffsantillan.com/blog/wp-content/uploads/2026/06/image-44-768x176.png 768w, https://jeffsantillan.com/blog/wp-content/uploads/2026/06/image-44-1300x298.png 1300w, https://jeffsantillan.com/blog/wp-content/uploads/2026/06/image-44.png 1511w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p class="wp-block-paragraph">Mensaje de error por que no se ingreso un nombre:</p>



<figure class="wp-block-image size-large"><img decoding="async" width="1024" height="215" src="https://jeffsantillan.com/blog/wp-content/uploads/2026/06/image-45-1024x215.png" alt="" class="wp-image-287" srcset="https://jeffsantillan.com/blog/wp-content/uploads/2026/06/image-45-1024x215.png 1024w, https://jeffsantillan.com/blog/wp-content/uploads/2026/06/image-45-300x63.png 300w, https://jeffsantillan.com/blog/wp-content/uploads/2026/06/image-45-768x161.png 768w, https://jeffsantillan.com/blog/wp-content/uploads/2026/06/image-45-1300x273.png 1300w, https://jeffsantillan.com/blog/wp-content/uploads/2026/06/image-45.png 1461w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p class="wp-block-paragraph">Mensaje de error por un email no valido.</p>



<figure class="wp-block-image size-large"><img decoding="async" width="1024" height="166" src="https://jeffsantillan.com/blog/wp-content/uploads/2026/06/image-46-1024x166.png" alt="" class="wp-image-288" srcset="https://jeffsantillan.com/blog/wp-content/uploads/2026/06/image-46-1024x166.png 1024w, https://jeffsantillan.com/blog/wp-content/uploads/2026/06/image-46-300x49.png 300w, https://jeffsantillan.com/blog/wp-content/uploads/2026/06/image-46-768x124.png 768w, https://jeffsantillan.com/blog/wp-content/uploads/2026/06/image-46-1300x210.png 1300w, https://jeffsantillan.com/blog/wp-content/uploads/2026/06/image-46.png 1465w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p class="wp-block-paragraph">Se logra la validación de manera exitosa.</p>



<pre class="wp-block-code has-small-font-size"><code>{
  "id": 1,
  "nombre": "Jeff",
  "email": "jeff@gmail.com",
  "edad": 25
}</code></pre>



<p class="wp-block-paragraph">¡Saludos!</p>
]]></content:encoded>
					
					<wfw:commentRss>https://jeffsantillan.com/blog/nestjs-uso-de-validator-y-transformers/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
			</item>
	</channel>
</rss>
