← Node & Express

Reto de código

crear un wrapper asyncHandler y un middleware de errores centralizado.

Reto: crear un wrapper asyncHandler y un middleware de errores centralizado.
Problema: en Express 4, si un handler async lanza un error (o su promesa se rechaza),
Express NO lo captura solo. La peticion se queda colgada. El wrapper lo soluciona.

Entrada / salida esperada:
  GET /ok    -> 200 { dato: "todo bien" }
  GET /falla -> 500 { error: "Algo salio mal" }   (el error se captura y se maneja)

Como probarlo:
  1. npm install
  2. node 06-retos-codigo/async-error-handler.js
  3. curl http://localhost:3000/ok
     curl http://localhost:3000/falla
Ver solución
// Reto: crear un wrapper asyncHandler y un middleware de errores centralizado.
// Problema: en Express 4, si un handler async lanza un error (o su promesa se rechaza),
// Express NO lo captura solo. La peticion se queda colgada. El wrapper lo soluciona.
//
// Entrada / salida esperada:
//   GET /ok    -> 200 { dato: "todo bien" }
//   GET /falla -> 500 { error: "Algo salio mal" }   (el error se captura y se maneja)
//
// Como probarlo:
//   1. npm install
//   2. node 06-retos-codigo/async-error-handler.js
//   3. curl http://localhost:3000/ok
//      curl http://localhost:3000/falla

const express = require("express");
const app = express();
const PORT = process.env.PORT || 3000;

// asyncHandler envuelve un handler async y captura cualquier rechazo,
// pasandolo a next(err). Asi Express puede enrutar el error al middleware
// de errores en lugar de dejar la peticion colgada.
// Promise.resolve(...) normaliza el retorno: funcione o no como promesa,
// .catch atrapa el error y lo reenvia a next.
function asyncHandler(fn) {
  return (req, res, next) => {
    Promise.resolve(fn(req, res, next)).catch(next);
  };
}

// Simula una operacion async que funciona (por ejemplo, leer de una BD).
async function operacionExitosa() {
  return { dato: "todo bien" };
}

// Simula una operacion async que falla.
async function operacionQueFalla() {
  throw new Error("fallo interno de la operacion");
}

// Ruta OK: sin wrapper tambien funcionaria, pero usamos el mismo patron.
app.get(
  "/ok",
  asyncHandler(async (req, res) => {
    const resultado = await operacionExitosa();
    res.status(200).json(resultado);
  })
);

// Ruta que falla: gracias al wrapper, el error llega al middleware de errores.
app.get(
  "/falla",
  asyncHandler(async (req, res) => {
    await operacionQueFalla(); // esto lanza; el wrapper lo captura
    res.json({ nunca: "se llega aqui" });
  })
);

// Middleware de errores CENTRALIZADO. Se reconoce porque tiene 4 parametros:
// (err, req, res, next). Express solo lo llama cuando algo pasa un error a next().
// Va SIEMPRE al final, despues de las rutas.
app.use((err, req, res, next) => {
  // En el servidor si registramos el error real para depurar.
  console.error("Error capturado:", err.message);

  // Al cliente NO le exponemos el stack ni detalles internos: solo un mensaje generico.
  res.status(500).json({ error: "Algo salio mal" });
});

app.listen(PORT, () => {
  console.log(`Servidor con manejo de errores async en http://localhost:${PORT}`);
});

module.exports = { app, asyncHandler };