Complete "Lección 2: Configuración de un proyecto Node.js y Express" primero para desbloquear esta lección.Ir a la lección anterior

Introducción

A medida que tu API crece más allá de unos pocos endpoints, volcar todo en un único archivo se vuelve ingobernable muy rápido. Express te ofrece una herramienta integrada llamada Router para dividir las rutas en módulos separados por recurso. Combínalo con una capa de controladores y obtendrás una estructura que escala de forma limpia: los nuevos miembros del equipo encuentran lo que necesitan, y añadir un recurso nuevo no obliga a modificar el código existente.

Esta lección recorre una disposición de proyecto concreta: las rutas definen los patrones de URL y los verbos HTTP, los controladores contienen la lógica de los handlers, y app.js los conecta. Esa separación es el hábito más importante que debes adquirir desde el principio.

diagrama de arquitectura en capas que muestra la Request entrando en app.js, luego la capa de Router, después la capa de Controller, y finalmente una capa de Datos como placeholder

Estructura del Proyecto

Esta es la disposición de directorios hacia la que vamos a construir:

text
project/
├── app.js
├── routes/
│ ├── users.js
│ └── products.js
└── controllers/
├── usersController.js
└── productsController.js

El patrón es simple: un archivo de rutas por recurso, un archivo de controladores por recurso. Las rutas se mantienen delgadas — solo declaran qué función del controlador gestiona cada endpoint. Los controladores se mantienen enfocados — solo contienen la lógica de request/response de su recurso.

Express Router

Express Router crea una mini-aplicación que gestiona rutas de forma independiente; luego la montas en una ruta dentro de app.js.

Comencemos con el archivo de rutas de usuarios:

javascript
// routes/users.js
const express = require('express');
const router = express.Router();
const usersController = require('../controllers/usersController');
router.get('/', usersController.getAllUsers);
router.get('/:id', usersController.getUserById);
router.post('/', usersController.createUser);
router.put('/:id', usersController.updateUser);
router.delete('/:id', usersController.deleteUser);
module.exports = router;

Observa que las rutas usan paths relativos como / y /:id, no /users ni /users/:id. El prefijo se añade cuando montas el router en app.js, así nunca te repites.

Montando el router en app.js:

javascript
// app.js
const express = require('express');
const app = express();
app.use(express.json());
const usersRouter = require('./routes/users');
const productsRouter = require('./routes/products');
app.use('/users', usersRouter);
app.use('/products', productsRouter);
app.listen(3000, () => console.log('Server running on port 3000'));

Una petición GET a /users/42 ahora se resuelve en router.get('/:id', ...) con req.params.id igual a '42'. Limpio y predecible.

Controladores

Los controladores son módulos simples que exportan funciones con nombre. Cada función es un handler estándar de Express: recibe req y res (y opcionalmente next) y se encarga de enviar la respuesta.

javascript
// controllers/usersController.js
// Simulated in-memory data — you will replace this with a database call later
const users = [
{ id: 1, name: 'Alice', email: 'alice@example.com' },
{ id: 2, name: 'Bob', email: 'bob@example.com' },
];
exports.getAllUsers = (req, res) => {
res.json(users);
};
exports.getUserById = (req, res) => {
const user = users.find(u => u.id === parseInt(req.params.id));
if (!user) {
return res.status(404).json({ message: 'User not found' });
}
res.json(user);
};
exports.createUser = (req, res) => {
const { name, email } = req.body;
if (!name || !email) {
return res.status(400).json({ message: 'name and email are required' });
}
const newUser = { id: users.length + 1, name, email };
users.push(newUser);
res.status(201).json(newUser);
};
exports.updateUser = (req, res) => {
const user = users.find(u => u.id === parseInt(req.params.id));
if (!user) {
return res.status(404).json({ message: 'User not found' });
}
const { name, email } = req.body;
if (name) user.name = name;
if (email) user.email = email;
res.json(user);
};
exports.deleteUser = (req, res) => {
const index = users.findIndex(u => u.id === parseInt(req.params.id));
if (index === -1) {
return res.status(404).json({ message: 'User not found' });
}
users.splice(index, 1);
res.status(204).send();
};

Hay varias cosas que vale la pena destacar aquí. El controlador valida la entrada y retorna pronto con un código de estado apropiado cuando algo falla — esto mantiene el camino feliz legible. La comprobación 404 es intencional: no asumas que un registro existe. Y un 204 No Content sin body es la respuesta convencional para un borrado exitoso.

diagrama de flujo que muestra una única petición HTTP entrante siendo emparejada por el Router con la función correcta del Controller, y luego bifurcándose en respuesta exitosa o respuesta de error

Errores Comunes

Olvidar parsear los cuerpos JSON de las peticiones es el problema más habitual entre principiantes. Sin app.use(express.json()) en app.js, req.body será undefined y createUser o updateUser recibirán silenciosamente nada.

Otra trampa es comparar req.params.id (un string) directamente con un id numérico usando igualdad estricta. La comprobación users.find(u => u.id === req.params.id) siempre fallará porque '42' !== 42. Usa parseInt o Number() para convertir primero.

Por último, no retornar después de enviar una respuesta provoca el error 'Cannot set headers after they are sent'. Usa siempre return res.status(404).json(...) — el return evita que Express continúe a la siguiente línea e intente enviar una segunda respuesta.

Resumen

Express Router te permite agrupar rutas relacionadas en sus propios módulos y montarlos en un prefijo dentro de app.js. Los controladores mantienen la lógica de los handlers fuera de los archivos de rutas, haciendo que cada capa sea más fácil de leer, testear y extender. El patrón es: el archivo de rutas declara la URL y el verbo, la función del controlador gestiona la lógica y envía la respuesta. Apégate a un archivo por recurso y aguantará bien a medida que el proyecto crezca.

Práctica de la lección

Punto de control de la lección

Repasa lo aprendido y recibe comentarios sobre tu trabajo.

0/1
Respondidas · 0/1
Lección 3: Enrutamiento, Controladores y Estructura del Proyecto