Desarrollar una API correctamente también implica manejar los errores que sus endpoints pueden tener de manera clara para el front-end.
Manejo de errores con NestJS
NestJS implementa de forma muy sencilla la posibilidad de responder con errores al cliente que realiza las consultas. Esto lo hace con una serie de clases que implementan los códigos HTTP correctos dependiendo el tipo de error que necesites.
import{NotFoundException}from'@nestjs/common';@Get('product/:idProduct')@HttpCode(HttpStatus.OK)asyncgetProduct(@Param('idProduct') idProduct: string): string {const product =awaitthis.appService.getProducto(idProduct);if(!product){thrownewNotFoundException(`Producto con ID #${idProduct} no encontrado.`);}return product;}
Importando NotFoundException puedes arrojar un error con la palabra reservada throw indicando que un registro no fue encontrado. Esta excepción cambiará el estado HTTP 200 que envía el decorador @HttpCode(HttpStatus.OK) por un 404 que es el correspondiente para la ocasión.
También puedes lanzar errores cuando el usuario no tiene permisos para acceder a un recurso.
import{ForbiddenException}from'@nestjs/common';@Get('product/:idProduct')@HttpCode(HttpStatus.OK)asyncgetProduct(@Param('idProduct') idProduct: string): string {// ...thrownewForbiddenException(`Acceso prohibido a este recurso.`);}
O incluso lanzar errores de la familia del 5XX cuando ocurre un error inesperado en el servidor.
import{InternalServerErrorException}from'@nestjs/common';@Get('product/:idProduct')@HttpCode(HttpStatus.OK)asyncgetProduct(@Param('idProduct') idProduct: string): string {// ...thrownewInternalServerErrorException(`Ha ocurrido un error inesperado.`);}
Explora todas las clases con estados HTTP que NestJS posee para desarrollar tus endpoints de manera profesional y manejar correctamente los errores.
SRC services
// src/services/products.service.tsimport{...,NotFoundException}from'@nestjs/common';@Injectable()exportclassProductsService{...findOne(id: number){const product =this.products.find((item)=> item.id=== id);if(!product){thrownewNotFoundException(`Product #${id} not found`);}return product;}update(id: number,payload: any){const product =this.findOne(id);const index =this.products.findIndex((item)=> item.id=== id);this.products[index]={...product,...payload,};returnthis.products[index];}remove(id: number){const index =this.products.findIndex((item)=> item.id=== id);if(index ===-1){thrownewNotFoundException(`Product #${id} not found`);}this.products.splice(index,1);returntrue;}}
Otra forma de manejar excepciones es con el modulo HttpException seria algo asi
aqui esta en la documentación
import{HttpException,HttpStatus}from'@nestjs/common';// DENTRO DE TU SERVICIO O CONTROLLERgetProducts(){thrownewHttpException('Error no se encontro',HttpStatus.BAD_REQUEST);}
muchas gracias
Como buena practica, los errores se pueden lanzar desde los proveedores o servicios, pero se deben atrapar en los controllers.
Con try catch
Un falso positivo xd
xd
Esas cosas son peligrosas
Un ejemplo con HttpException retornando un NOT_FOUND
<code>import{HttpException,HttpStatus,Injectable}from'@nestjs/common';import{Product}from'src/entities/product.entity';// SERVICEfindOne(id: number){const product =this.products.find((item)=> item.id=== id
);if(!product)thrownewHttpException('Product not found',HttpStatus.NOT_FOUND);return product
}
No se totea ! jejeje
Me imagino que quiso decir que no rompe.
Por qué en nestjs se pasan los parametros númericos con un "+"? por ejemplo:
Esto va más alla del framework de Nest en sí y es propio del lenguaje Javascript, es un operador unario y según mdn:
++Operador unario: Intenta convertir el operando en un número, si aún no lo es.++
Si falla devuelve un NaN
Te dejo más info de esto aquí, yo tampoco conocía este truco.
Los parámetros que llegan a través de la URL siempre son strings, aun si los tipeas como number, por eso te marca error de tipeado ya que en el servicio estas esperando un number. Puedes comprobarlo imprimiendo el tipo de la variable 'id'.
console.log(typeof productId);
El operador '+' te permite convertir el valor a un número.
Al momento de manipular los errores con el kit que nos ofrece Nest, me surge una duda, quien debería de ser el encargado de generar dichos errores, los servicios o los controladores?
Me doy cuenta que en el servicio tiene más sentido porque nos permite reutilizar las funciones y al mismo tiempo reutilizar las comprobaciones y validaciones, pero me gustaría estar seguro.
Si es correcto normalmente se tienen este manejo de errores en los servicios, ya que allí también tienes la lógica de negocio, los controladores se encargan más de validaciones de datos con los DTOs y permisos como Auth (Los permisos de Auth los vemos en curso específico de eso ) https://platzi.com/cursos/nestjs-auth/
Muchas gracias! estoy emocionado por ese curso, estoy ansioso que este disponible!
Ya que usa findOne() no veo pq volver a user findIndex. Se podria reescribir así:
Inicialmente no se elminaba el producto por la triple comparacion === pero luego de agregar ParseIntPipe al decorador Param funcionó correctamente
delete(@Param("productId",ParseIntPipe) productId: number){//Code here }
Nicolas:
En una anterior pregunta leo que aconsejas manejar los errores en el service, sin embargo en la documentación de Nest parecen aconsejar el uso de Exception filters en el controller:
Por favor podrías aclararnos esta duda..
Me gustaría poder manejar todos los errores, no solo el NotFoundException y ademas mandar la información al Logger.
Sin embargo si quieres hacer manejo de expeciones más complejas o como mencionas puedes crear tu propio Exception filter sin embargo para manejar un logger puede servir mejor un Interceptor de NestJS.
Un mi caso suelo usar este paquete creado por la comunidad @ntegral/nestjs-sentry para detectar los errores y enviarlos a Sentry y dentro de ese paquete uso por ejemplo a
SentryInterceptor.
Si tengo un campo llamado estado y si tiene que devolver false puedo devolver NotFoundException cuando el objeto si exite? es decir si el estado es true quiero recien devolver el 200.
O eso rompe con con lo que es la respuesta en si?
Hola si claro tú puede retornar un NotFoundException desentendiendo de una propiedad del objeto sin problema.
Hola, que es totear?
reventar o romper
Tengo un problemita con la respuesta, primero me parece diferente a la clase, es como muy repetitiva ya que aparecen variosdos veces el estatus de error y el mensaje, ademas postman me marca como status 200, no deberia ser 404?
Si lo que pasa es que no tienes que retornar el error tienes que solo lanzarlo como tal:
thrownewNotFoundException('Mi message');
Sin el return
No es mejor manejar los errores en el servicio? y desde el controlador hacer un return del servicio? Para que quede más limpio el controller y en el servicio toda la lógica con las excepciones, como por ejemplo un throw new NotFoundException o el error que sea
El problema de usar NotFoundException en el servicio es que el servicio pasa a ser un eslabón dependiente de nuestra REST API, lo ideal es desde el servicio se disparen errores específicos no de la API sino del servicio (personalizados) y luego en el controlador manejemos los errores de la REST API
Se puede manejar el error en una función aparte y donde se requiera validar si existe el producto, llamar a la función:
validateIfProductExist(id: string) { const product = this.products.find((product) => product.id === id); if (!product) { throw new NotFoundException({ status: HttpStatus.NOT_FOUND, error: `The product with id: ${id} was not found`, }); } }
creo que esto vendría siendo una desventaja de nest. Entiendo que cuando mando el error desde el servicio en la respuesta me aparece el código correcto. Pero en el controler sigo enviando en el HttpCode una respuesta positiva. La verdad me confunde un poco.
Hasta ahora me ha encantado nest, pero esto me parece un poco raro
Como así ? No te capte muy bien la duda
Los errores de propagan sí no hay algo que los capture, en el caso del ejemplo del video, el error es recibido en el lado del cliente, por cual es correcto, ya que no continuaría con el siguiente código después de lanzar el error.
HttpCode será nuestra respuesta por defecto, la cual esperamos sea positiva siempre, por ello se coloca como principal, sin embargo, con lo de las excepciones este httpCode será reemplazado por el error que hayamos lanzado. No le veo desventaja desde mi visión.
Manejar error de eliminar un producto que no existe
implementación del servicio remove borrar un producto en el el controlador