Express Async Error Handling Wrapper

Route async failures into Express error middleware with a wrapper, classify status codes, and mask internal details before responding.

JavascriptNodeResilience

Code

snippet
import express from 'express';

class HttpError extends Error {
  constructor(status, message, public detail = null) {
    super(message);
    this.status = status;
    this.detail = detail;
  }
}

const wrap = (handler) => (req, res, next) => {
  Promise.resolve(handler(req, res, next)).catch(next);
};

const app = express();
app.use(express.json());

app.get('/orders/:id', wrap(async (req, res) => {
  const order = await findOrder(req.params.id);
  if (!order) throw new HttpError(404, 'order not found');
  res.json(order);
}));

app.use((err, req, res, next) => {
  const status = err instanceof HttpError ? err.status : 500;
  if (status >= 500) console.error('unhandled:', err.stack);
  res.status(status).json({
    error: err.message || 'internal error',
    detail: status < 500 ? err.detail : undefined,
  });
});

async function findOrder(id) {
  if (id === 'missing') return null;
  return { id, total: 42 };
}

app.listen(3000);