Cómo enviar errores al usuario en Nest levantando excepciones que el propio Framework es capaz de tratar de manera automática y devolver mensajes descriptivos a los usuarios y clientes de las API.
En el artículo anterior creamos la base de código esencial para hacer un controlador que implementa las operaciones CRUD, apoyándose en un servicio. Dijimos que una de las cuestiones que nos había faltado implementar consistía en la realización de algunas comprobaciones básicas y necesarias antes de poder hacer las operaciones solicitadas.
En este ejercicio vamos a agregar algo de lógica a un servicio creado en Nest que nos permitan realizar comprobaciones esenciales sobre la entrada de datos, necesarias antes de hacer las operaciones.
La importancia de gestionar errores
En las aplicaciones es necesario realizar las comprobaciones oportunas para poder responder a nuestros usuarios con mensajes de éxito o errores descriptivos.
Por ejemplo, al intentar recuperar datos de un producto determinado, no podríamos devolver un elemento de Products si el identificador al que intentamos acceder no existe. Todo esto lo tenemos que verificar para ofrecer respuestas adecuadas a nuestros clientes.
Cómo Nest nos ayuda para devolver errores de una manera cómoda
NestJS ofrece toda una cantidad de excepciones útiles para devolver errores a nuestros usuarios / clientes, que están preparadas para informar de una manera adecuada ante posibles situaciones de error.
Algunas de estas excepciones son BadRequestException, NotFoundException, ForbiddenException... pero hay muchas más.
Todas estas excepciones levantan errores que ya están configurados de manera básica para funcionar de una u otra forma, por lo que la cantidad de datos que necesitamos pasarles son bastante acotados.
Como desarrolladores, podemos levantar estas excepciones en cualquier lugar del código, es decir, desde cualquier clase por la que pase el flujo de ejecución en una solicitud. Los servicios son un lugar adecuado para levantar excepciones, cuando la lógica de nuestros programas lo requiera.
Filtros de excepción en Nest
Como sabes, las excepciones requieren usar bloques try ... catch para poder tratarlas convenientemente y que no se produzcan errores que interrumpan la ejecución de los programas. Tratar excepciones es a veces una tarea tediosa, pero afortunadamente Nest nos facilita mucho este trabajo.
Los filtros de excepción (o exception filters) consisten en una capa de procesamiento automático de las excepciones no tratadas que se producen en las aplicaciones. Cualquier excepción que no haya sido tratada en tu propio código se capturará por los filtros de excepciones y devolverá el mensaje apropiado a los clientes como respuesta.
Por tanto, Nest nos permite olvidarnos del tratamiento de las excepciones y dejar al framework que produzca los mensajes de error adecuados.
Cómo levantar una excepción en un servicio
Ahora vamos a ver cómo levantar una excepción en un servicio. Para ello vamos a mejorar el código que hemos realizado hasta el momento en el método getId().
Este método está preparado para devolver el objeto producto de un identificador dado. Pero antes de devolver nada, vamos a comprobar si realmente existe ese identificador en el sistema.
El código que hemos preparado está aquí:
getId(id: number): Product {
const product = this.products.find( (item: Product) => item.id == id);
if(product) {
return product;
} else {
throw new NotFoundException(`No encontramos el producto ${id}`);
}
}
Primero intentamos buscar el producto, con el método find() sobre el array de productos. Esto ya lo hacíamos antes. A continuación preguntamos si el producto existe, con el if. En caso positivo simplemente devolvemos ese producto. En caso que no exista el producto, entonces levantamos una excepción.
Como hemos dicho, existen diversos construtores de excepciones, configurados de manera variable. Aquí resultaría útil levantar una excepción de "no encontrado", que lo conseguimos con "NotFoundException".
throw new NotFoundException(`No encontramos el producto ${id}`);
Con throw se levantan excepciones en Javascript
NotFoundException es una clase que hereda de HttpException, que a su vez hereda de Error, que es la clase base de los errores Javascript.
El constructor de NotFoundException requiere el mensaje que queremos enviar al usuario o cliente de nuestra API.
Cómo se envían los errores al cliente
Nest es el encargado de enviar los errores al usuario, gracias a su capa de tratamiento de excepciones.
En realidad sería más correcto decir que los errores se envían al cliente, ya que no siempre va a ser un usuario (una persona) el que se conecte con la aplicación, sino un cliente cualquiera que esté usando el API.
Por tanto, aunque el error lo hemos generado en el servicio y no estemos devolviendo una respuesta adecuada al controlador, no necesitamos preocuparnos. Es decir, no necesitamos tratar la excepción en el controlador, sino que uno de los filtros de excepción de Nest se encargará de generar el correspondiente error.
Así es como un error se mostrará a nuestros clientes. Para ello simplemente vamos a intentar acceder a un producto que no existe.
http://localhost/products/100001
Si ese producto no se encuentra entre el array que maneja el servicio, lo que es bastante probable, entonces se levantará la excepción NotFoundException y se devolverá un status code 404, junto con el mensaje de error que hemos configurado.
Esta request en Postman nos aparecerá más o menos así:
Fíjate en la imagen que el status code es 404, el adecuado para los errores "Not found" y que además nos devuelve un cuerpo en la solicitud con el mensaje que hemos configurado para esta excepción.
Si lo deseamos, el constructor de la excepción NotFoundException puede recibir un segundo parámetro para indicar el código de error que queremos dar a nuestros usuarios.
throw new NotFoundException(`No encontramos el producto ${id}`, "No encontrado");
En este caso, el body mostrará un código de error como este:
{
"statusCode": 404,
"message": "No encontramos el producto 1000001",
"error": "No encontrado"
}
El status code seguirá siendo 404, solo que hemos colocado de manera personalizada la propiedad "error", con un código en español.
Usando HttpException de manera genérica
Todas las clases de excepciones de Nest heredan de HttpException, que es una clase para generación de errores genéricos, totalmente configurables por nosotros.
En este ejemplo vamos a modificar el método delete() del servicio, que se encargará de comprobar si existe el recurso que se quiere borrar. Si no existe, vamos a devolver un mensaje de error que nos indique que no existía ese recurso.
Podríamos perfectamente usar de nuevo NotFoundException(), pero vamos a conseguir un tratamiento similar pero más genérico con HttpException.
El código de nuestro método podría quedar así:
delete(id: number) {
const product = this.products.find((item: Product) => item.id == id);
if(product) {
this.products = this.products.filter( (item: Product) => item.id != id );
} else {
throw new HttpException(`No existe el producto ${id}`, HttpStatus.NOT_FOUND);
}
}
Como ves, hemos levantado la excepción de tipo "HttpException", que requiere solamente dos parámetros, primero el mensaje y luego el código de error HTTP de esta excepción genérica.
Veremos cómo conseguimos una respesta en Postman muy similar a la de NotFoundException, pero en la práctica podríamos construir la respuesta usando cualquier otro status del HTTP, ya que "HttpException" no obliga a que sea uno determinado.
Conclusión
Hemos aprendido a levantar excepciones para informar de errores a nuestros clientes. Las excepciones no las necesitamos tratar nosotros mismos con el correspondiente bloque try/catch, sino que dejamos al framework que se encargue de su tratamiento con los "exception filters".
Hemos aprendido que podemos tratar las excepciones con clases que tienen una completa configuración ya implementada, como es el caso de NotFoundException. Además, hemos visto que de una manera muy similar podemos usar HttpException, que permite una mayor personalización del status de la respuesta.
Con esto hemos cubierto una buena cantidad de información con respecto a los servicios y los flujos de trabajo necesarios para coordinarse con los controladores y responder a posibles errores básicos. En el siguiente artículo pasaremos a trabajar con otros artefactos existentes en Nest, como son los módulos.
Miguel Angel Alvarez
Fundador de DesarrolloWeb.com y la plataforma de formación online EscuelaIT. Com...