No tienes acceso a esta clase

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

Crea tu propio pipe

18/23
Recursos

Crear tus propias validaciones de datos será muy importante para segurizar tu aplicación y evitar errores inesperados.

Cómo crear custom PIPES

Crea tu propio PIPE para implementar lógica custom de validación de datos.

1. Crea tu primer Pipe

Con el CLI de NestJS autogenera un nuevo pipe con el comando nest generate pipe <pipe-name> o en su forma corta nest g p <pipe-name>.
Por defecto, verás un código como el siguiente.

import { ArgumentMetadata, Injectable, PipeTransform } from '@nestjs/common';

@Injectable()
export class ParseIntPipe implements PipeTransform {

  transform(value: any, metadata: ArgumentMetadata) {
    return value;
  }
}

2. Implementa la lógica del Pipe

Implementa aquí tu propia lógica de transformación y validación de datos. Ten en cuenta que si los datos no son válidos, puedes arrojar excepciones para informarle al front-end que los datos son erróneos.

import { ArgumentMetadata, Injectable, PipeTransform, BadRequestException } from '@nestjs/common';

@Injectable()
export class ParseIntPipe implements PipeTransform {

  transform(value: string, metadata: ArgumentMetadata) {
    const finalValue = parseInt(value, 10);
    if (isNaN(finalValue)) {
      throw new BadRequestException(`${value} no es un número.`);
    }
    return finalValue;
  }
}

3. Importa y utiliza el Pipe

Finalmente, implementa tu custom PIPE en el controlador.

import { ParseIntPipe } from './pipes/parse-int.pipe';

@Get('product/:idProduct')
getProduct(@Param('idProduct', ParseIntPipe) idProduct: string): string {
    // ...
}

Puedes desarrollar la lógica para validar y transformar los datos que más se adecue a tus necesidades. Es fundamental no permitir el ingreso de datos erróneos a tus controladores. Por eso, los pipes son una capa previa a los controladores para realizar esta validación.

Generar un pipe con nest g pi common/parse-int

// src/common/parse-int.pipe.ts

import {
  ArgumentMetadata,
  Injectable,
  PipeTransform,
  BadRequestException,
} from '@nestjs/common';

@Injectable()
export class ParseIntPipe implements PipeTransform {
  transform(value: string, metadata: ArgumentMetadata) {
    const val = parseInt(value, 10);
    if (isNaN(val)) {
      throw new BadRequestException(`${value} is not an number`);
    }
    return val;
  }
}

Contribución creada por: Kevin Fiorentino.

Aportes 25

Preguntas 9

Ordenar por:

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

Puedes crear tus propios pipes para crear validaciones y transformaciones personalizadas.

nestjs se trae la esencia de angular, es una maravilla!

También puedes usar el objeto Number(), para parsear la string numérica, con este objeto también evitas que parseInt te haga el parse cuando envías un número con letras.
Number()

Una curiosidad de parseInt(), que descubri probando (tal vez muchos ya la sepan, pero para mi es nuevo), es que si (en el argumento) tienes un string empezando por un numero y luego un caracter alfanumerico, devuelve el numero antes del primer caracter no numerico.
Ej.: si tienes

parseInt('12yletras')
devuelve --> 12

Bueno espero les sirva, saludos!
PD.: Me esta gustando mucho el curso hasta ahora! 👍️

Los pipes tienen dos funciones principales validar y transformar.

Importarlo

import { ParseIntPipe, } from '@nestjs/common';

Implementarlo

@Get(':productId')
@HttpCode(HttpStatus.ACCEPTED)
getProduct(@Param('productId', ParseIntPipe) productId: number) {
  return this.productService.findOne(productId);
}

Custom pipes

Tambien se puede crear un pipe customizable:

  • Con el comando: nest g pipe common/parse-int
CREATE src/common/parse-int.pipe.spec.ts (173 bytes)
CREATE src/common/parse-int.pipe.ts (224 bytes)
  • Crea el siguiente codigo del pipe
import { ArgumentMetadata, Injectable,PipeTransform, } from '@nestjs/common';

@Injectable()
export class ParseIntPipe implements PipeTransform {
  transform(value: string, metadata: ArgumentMetadata) {
    return value;
  }
}
  • reescribiendo el parseInt:
import {
  ArgumentMetadata,
  Injectable,
  PipeTransform,
  BadRequestException,
} from '@nestjs/common';

@Injectable()
export class ParseIntPipe implements PipeTransform {
  transform(value: string, metadata: ArgumentMetadata) {
    const val = parseInt(value, 10);
    if (isNaN(val)) {
      throw new BadRequestException(`${value} is not number`);
    }
    return val;
  }
}

Pipes que tiene nestjs https://github.com/nestjs/nest/tree/master/packages/common/pipes

Agregue una validacion extra para el parseintpipe por que cuando ingresaba numeros con una letra o muchas letras no me lograba atrapar el error.
 
Este es mi codigo:

  transform(value: string, metadata: ArgumentMetadata) {
    const val = parseInt(value, 10);

    if (isNaN(val) || /\D/.test(value)) {
      throw new BadRequestException(`${value} is not a number.`);
    }

    return val;
  }

con el comando de la clase para el pipe se crea una subcarpeta, por lo que el import sería:

import { ParseIntPipe } from '../common/parse-int/parse-int.pipe';
 
¿ID entero o ID alfanumérico? La decisión de manejar la validación de diferentes tipos de ID (como enteros para SQL o cadenas alfanuméricas para MongoDB) dentro de un mismo Pipe o en Pipes separados depende del diseño de tu aplicación, la claridad del código y el principio de responsabilidad única (Single Responsibility Principle - SRP) ```js @Injectable() export class ValidateIdPipe implements PipeTransform { transform(value: string, metadata: ArgumentMetadata) { const isMongoId = /^[a-fA-F0-9]{24}$/.test(value); // Valida formato de ObjectId de MongoDB const isInt = /^[0-9]+$/.test(value); // Valida números enteros if (!isMongoId && !isInt) { throw new BadRequestException( `${value} no es un ID válido. Debe ser un número entero o un ObjectId.`, ); } return isInt ? parseInt(value, 10) : value; // Devuelve el número entero o la cadena alfanumérica } ```**Recomendación práctica** Para proyectos con arquitecturas grandes o en crecimiento, suele ser mejor separar los Pipes por tipo de ID. Esto mejora la escalabilidad y el mantenimiento del código. Sin embargo, si manejas ambos tipos de ID en un único endpoint y deseas simplicidad, un Pipe unificado puede ser una solución adecuada.
`export class ParseIntegerIdPipe implements PipeTransform {` ` transform(value: any, metadata: ArgumentMetadata) {` ` const reg = /^\d+$/;` ` if (!reg.test(value)) {` ` throw new BadRequestException('Is not an integer');` ` }` ` return parseInt(value, 10);` ` }` `}`
puedes utilizar `npx` para ejecutar el comando `nest` sin la necesidad de instalarlo globalmente. Aquí está el comando que puedes utilizar para generar el pipe: `npx @nestjs/cli generate pipe common/parse-int`

Le pregunte a chatgpt como se testea ese pipe y me arrojo esto

import { ArgumentMetadata, BadRequestException } from '@nestjs/common';
import { ParseIntPipe } from './parse-int.pipe';

describe('ParseIntPipe', () => {
  let pipe: ParseIntPipe;

  beforeEach(() => {
    pipe = new ParseIntPipe();
  });

  it('should be defined', () => {
    expect(pipe).toBeDefined();
  });

  it('should transform a valid numeric string into an integer', () => {
    const value = '42';
    const metadata = {} as ArgumentMetadata;
    const expectedOutput = 42;
    const result = pipe.transform(value, metadata);

    expect(result).toEqual(expectedOutput);
  });

  it('should throw a BadRequestException for an invalid numeric string', () => {
    const value = 'invalid';
    const metadata = {} as ArgumentMetadata;

    expect(() => {
      pipe.transform(value, metadata);
    }).toThrow(BadRequestException);
  });
});

Si queremos usar pipes con parametros o queries que son opcionales, podemos aplicar algo como esto:

products.controller.ts

  @Get()
  getProducts(
    @Query('limit', new ParseIntPipe(false)) limit = 100,
    @Query('offset', new ParseIntPipe(false)) offset = 0,
    @Query('brand') brand: string,
  ) {
    return this.productsService.findAll();
  }

parse-int.pipe.ts

@Injectable()
export class ParseIntPipe implements PipeTransform {
  constructor(private isRequired: boolean) {}

  transform(value: string, metadata: ArgumentMetadata) {
    const val = Number(value);
    if (isNaN(val) && this.isRequired) {
      throw new BadRequestException(
        `Validation failed. ${value} is not a number`,
      );
    }
    return val;
  }
}

import { ArgumentMetadata, Injectable, PipeTransform, BadRequestException } from ‘@nestjs/common’;

@Injectable()
export class ParseIntPipe implements PipeTransform {

transform(value: string, metadata: ArgumentMetadata) {
const finalValue = parseInt(value, 10);
if (isNaN(finalValue)) {
throw new BadRequestException(${value} 👀 Tiene que ser de tipo numero el /id.);
}
return finalValue;
}
}

ame este curso

Tambien es posible pasar varios Pipes, de esta manera

ya me dieron ganas de aprender angular

me pareció muy llamativa la validación que Nest hace para saber si es numérico un valor.

Se parece a los pipes de angular

Crea tu propio Pipe

Puedes crear tus propios pipes para crear validaciones y transformaciones personalizadas.

Desde la terminal ejecutamos el siguiente comando:

nest g pipe common/parse-int

Nos creara dentro de la carpeta common dos archivos unos para el desarrollo de nuestro pipe y otro para la pruebas correspondientes

Dentro del archivo parse-int.pipe.ts vamos a desarrollar un pipe para convertir de string a number:

export class ParseIntPipe implements PipeTransform {
  transform(value: string, metadata: ArgumentMetadata) {
		const val = parseInt(value, 10);
		if(isNaN(val)){
			throw new BadRequestException(`El valor is not an number`)
		}
    return val;
  }
}

luego simplemente lo importamos en nuestro controlador y hacemos uso del pipe:

import { ParseIntPipe } from './../../common/parse-int.pipe'

@Get(':productId')
	@HttpCode(HttpStatus.ACCEPTED)
	getOne(@Param('productId', ParseIntPipe) productId: number) {
		return this.productsService.findOne(productId);
	}

es como Angular pero para el Backend!

Revisar el repositorio de Nest Js directamente en la carpeta Common puedes visualizar todos los PIPES ya pre-construidos por defecto.

Utilizar el PIPE que creamos para validar y transformar

Lanzar excepcion BadRequestException cuando no es posible transformar el dato al tipo correcto

Generar un nuevo PIPE (Validar y Transformar) desde el CLI

nest generate pipe common/parse-int -flat

👏