Estructura MVC para APIs Express
Estructura
Sección titulada «Estructura»src/├── app.ts # express(): middlewares globales + montaje de rutas├── server.ts # listen, conexión DB, shutdown limpio├── config/ # env, constantes├── routes/ # solo definición de endpoints → controllers│ └── users.routes.ts├── controllers/ # req/res: parsean entrada, llaman services, responden│ └── users.controller.ts├── services/ # lógica de negocio, orquestación│ └── users.service.ts├── repositories/ # acceso a datos (Prisma, SQL, etc.)│ └── users.repository.ts├── middlewares/ # auth, validación, errores, logging├── utils/ # helpers puros└── types/ # tipos y DTOs compartidosFlujo de una request
Sección titulada «Flujo de una request»Request → route (método + path, aplica middlewares) → middleware (auth, validación) → controller (adapta HTTP → service, nunca toca la DB) → service (reglas de negocio) → repository (consultas) → controller (formatea respuesta + status)- El controller es la única capa que conoce
req/res. - La DB solo se toca en repositories → cambiar de ORM no rompe services.
- Los errores se lanzan en services y los formatea un middleware de error central; no try/catch por todas partes.
Error handler central
Sección titulada «Error handler central»import type { ErrorRequestHandler } from "express"
export const errorHandler: ErrorRequestHandler = (err, _req, res, _next) => { const status = err.status ?? 500 res.status(status).json({ error: status === 500 ? "Error interno" : err.message })}Se registra al final, después de todas las rutas: app.use(errorHandler).