¿Cómo implementar middlewares para manejo de errores en JavaScript?
Los middlewares son una herramienta poderosa al desarrollar aplicaciones en JavaScript. Entre sus múltiples usos, se destacan los middlewares para manejo de errores, que ayudan a capturar, formatear y gestionarlos de manera uniforme. En esta guía aprenderás cómo implementar y utilizar middlewares que capturen y gestionen errores de forma global en tu aplicación.
¿Cómo configurar y comenzar con middlewares de error?
La implementación de un middleware para manejo de errores comienza por organizar el código en una estructura limpia. Es recomendable crear una carpeta dedicada exclusivamente para los middlewares, asegurando una separación adecuada del código.
Crear una carpeta para middleware:
Ubica la carpeta en la raíz del proyecto para una fácil localización.
Dentro de esta carpeta se alojarán los archivos correspondientes a cada middleware.
Implementar el primer middleware:
Crea un archivo llamado errors.js dentro de la carpeta de middlewares.
Define una función para loguear errores, llamándola logErrors. Esta función capturará el error y lo desplegará en la consola. A continuación se presenta un ejemplo de cómo se vería esta función:
Añadir middlewares a la aplicación: Usa el método app.use() para incluir los middlewares en tu aplicación express:
app.use(logErrors);app.use(errorHandler);
Verificar el orden de ejecución: Asegúrate de incluir los middlewares en el orden adecuado. Esto es crucial, ya que el primer middleware logErrors debe ejecutarse antes que errorHandler. Puedes verificar el orden mediante logs en la consola.
¿Cómo manejar errores de forma explícita en el routing?
Para detectar y gestionar errores de manera efectiva, es necesario realizar algún manejo de errores a nivel de las rutas.
Integrar try-catch en las rutas: Un método efectivo es envolver el código de tu controladores de ruta en bloques try-catch. De esta manera, los errores se pueden capturar y enviar explícitamente a través de next(err) para que sean manejados por los middlewares:
app.get('/productos/:id',async(req, res, next)=>{try{// lógica de obtención de producto}catch(err){next(err);// Envía el error a los middlewares de manejo de error.}});
¿Cómo mejorar el tratamiento de errores?
Una buena práctica es utilizar códigos de estado HTTP para comunicar correctamente la naturaleza del error al cliente y evitar asignar siempre un error 500. Por ejemplo:
404: Producto no encontrado.
409: Conflictos que indican alguna restricción de negocio que no se cumple.
401 o 403: Falta de permisos.
Asegúrate de adaptar la gestión de errores para utilizar los códigos de estado más adecuados, maximizando la claridad para el cliente y facilitando el mantenimiento.
Implementar middlewares para errores es un paso esencial hacia una aplicación robusta y profesional. Sigue explorando estas técnicas avanzadas para optimizar tu desarrollo en JavaScript. ¡Continúa aprendiendo y perfeccionando tus habilidades en cada clase!
Espero les sirvan mis apuntes:
Crear middleware de tipo error:
//Creamos función que nos hará llegar a un middleware de tipo error:functionlogErrors(err, req, res, next){console.error(err);//mostrar el error en servidor para poder monitorearlonext(err);//importante para saber que se esta enviando a un middleware de tipo error, si no tiene el error dentro entonces se esta mandando a uno normal}// Crear formato para devolverlo al cliente que se complementa con la función anterior:functionerrorHandler(err, req, res, next){//así no se utilice next en el código se debe poner aqui, ya que un middleware de error tiene los cuatro parámetros res.status(500).json({//indicar que el error es estatus 500 Internal Server Errormessage: err.message,//mostrar al cliente el mensaje de errorstack: err.stack,//mostrar info del error})}module.exports={ logErrors, errorHandler };//exportarlo como modulo
Implementar middleware:
// Importar middlewareconst{ logErrors, errorHandler }=require('./middlewares/errorHandler');//importar las funciones que se uilizarán
Los middlewares de tipo error siempre deben ir después de definir el routing.
routerApi(app);// Utilizamos los middleware. Siempre deben ir después del routing:app.use(logErrors);app.use(errorHandler);
Es importante el orden en que se coloquen porque es el orden en que se ejecutarán. En este caso el logErrors es el único con un next, por lo tanto, si se colocará el errorHandler antes, ahí terminaría el proceso.
Además de lo anterior, el error se debe capturar de forma explicita en el router:
// Encontrar un producto por su id:router.get('/:id',async(req, res, next)=>{//se agrega el nexttry{const{ id }= req.params;const product =await service.findOne(id); res.json(product);}catch(error){next(error);//se agrega el next para atrapar de forma explicita el error con el middleware}});
buen aporte, esto: Los middlewares de tipo error siempre deben ir después de definir el routing.
routerApi(app);
debe ir arriba de nuestros middlewares.
routerApi(app);
...middlewares
::::::::::: Muchas gracias por tus apuntes y grandes aportes compañero :::::::::
500 Internal Server Error
Como metieron ese gato ahi?
Importantísimo el manejo de errores con sus respectivos status dependiendo del error.
Para complementar tu aporte 😊
HTTP response status codes - HTTP | MDN
HTTP Status Codes
Gracias por el aporte!
El problema por el que no funcionaba el middleware por defecto es porque la función es asíncrona.
Buscando un poco encontré que Express por defecto no pasa los errores asíncronos a los middleware de error, por lo que había que capturar el error y pasarlo al next en cada función de routing, como se hace en la clase. Pero eso debería hacerse en cada función controller, haciéndose repetitivo. Encontré este paquete que agrega a express la forma de manejar los errores asíncronos, así el middleware funcionará como esperábamos.
npm install express-async-errors
Solo debemos importarlo en el index.js y la función de routing quedará como estaba.
require("express-async-errors");
Gracias por el aporte, llevaba un rato comparando el código y no entendía la diferencia.
Buen aporte, así se evita poner trycatch en cada controller
El middleware de manejo de errores se define al final, después de otras llamadas de rutas y app.use(); por ejemplo:
Realmente no veo error evidente en código que nos compartes, pero que parece raro que en tu flujo no hay un lanzamiento de error y la app se rompe, ¿Nos puedes compartir tu repo?
a mi me había salido un error así, lo que hice fue quitar el async, intenta quitarlo de tu función find
Yo que vengo de otros lenguajes, veo a los Middlewares como un interceptor. En donde toma la petición http (Caso de Uso) hace algo con eso, y la procesa o descarta.
👽 Quizás este equivocado, pero lo veo así.
Importante: Los middlewares de error deben ejecutarse después de definir el routing. De no ser así no serán capturados (No funcionará).
Yo tuve problemas con el error middleware, no lo estaba tomando.
hasta que me di cuenta que era un problema con la firma
y encontre esto en la documentación
Error-handling middleware always takes four arguments.You must provide four arguments to identify it as an error-handling middleware function.Evenif you don’t need to use the next object, you must specify it to maintain the signature.Otherwise, the next object will be interpreted as regular middleware and will fail to handle errors.
siempre hay que agregar los cuatro parámetros aunque no se usen
Mi error handler:
Mi Index implementando error handler:
Mi servicio arrojando errores como todo un campeon:
Mi router implementando el error handler a trav'es de next:
Yo parando la clase para revisar como podria hacer handling de los diferentes status de errores y despues de romperme la cabeza, sigo viendo el video y me doy cuenta que el profe lo reconoce y dice que lo vamos a trabajar...
Esto de los middlewares me esta volando la cabeza!! 🤯 Creo que es porque son algo bastante abstracto que Express maneja internamente. Sin embargo, me parece una funcionalidad muy útil de este framework, no se a ustedes.
Entonces los Middleware funcionan casi como interceptors ?
Hola, si es correcto es una forma de interceptar las peticiones y con eso ver si lo dejas o no pasar al siguiente paso.
Por que los middlewares de error deben ir al final de las rutas?
Es para asegurarte solamente que el error sea capturado correctamente :) si el middleware estuviera antes que las rutas y alguna ruta lanzara un error hay probabilidad de que el middleware de error no atrape la excepción generada dentro de las rutas.
El profe no puso los middlewares despues de los routes? No se supone que nunca deberian ser llamados esos middlewares?
Si realmente si se pusieron en la línea 22 y 23 en el minuto 5:29, si es a lo que te refieres?
app.use(logErrors);app.use(errorHandler);
@nicobytes Si, y la funcion "routerApi" es llamada en la linea 19. Crei que todos los middlewares debian ser colocados antes de asignar una ruta, incluso los error middlewares.
Para la ejecución de middlewares en Express.js, se mencionaron algunas consideraciones importantes:
Orden de ejecución: Los middlewares de tipo error deben definirse después de las rutas. El orden en que se colocan en el código determina el flujo de ejecución.
Middlewares de error: Es esencial usar los middlewares de tipo error al final, ya que si un middleware de error no llama a next(), la ejecución se detiene.
Manejo de errores específicos: En lugar de enviar un error genérico 500, se recomienda utilizar códigos de estado adecuados (como 404 para "no encontrado" o 409 para "conflictos") según la situación.
Estas prácticas te ayudarán a gestionar mejor los errores y mejorar la experiencia de tu API.