🎯 Objetivo del tema
El administrador aún no ha insertado un video para esta sección.
🗺️ Mapa del tema
En el Tema 2.6 creaste un servidor HTTP nativo con Node. Funcionaba, pero era verboso: tenías que parsear la URL manualmente, manejar Content-Type, hacer if/else para cada ruta. Express es una capa delgada sobre Node que te da una API más limpia, routing expresivo, middleware reutilizable, y mucho menos código boilerplate. Es el estándar de facto para APIs en Node.js desde 2010.
El framework minimalista que te ahorra 200 líneas de boilerplate.
5 líneas para tener un servidor con routing básico.
Cómo organizar las rutas de tu API de forma limpia.
Funciones que se ejecutan en cadena: logger, auth, parse, etc.
Los objetos que Express te da en cada handler.
Try/catch, async/await en handlers, y el middleware de errores.
2.7.1 Qué es Express y por qué usarlo
Express es un framework minimalista para Node.js: añade una capa de azúcar sobre el módulo http nativo, sin opacar la libertad de Node. Es OPINIONATED solo en lo esencial: routing con métodos HTTP, middleware encadenable, y req/res con propiedades útiles. Lo demás (bases de datos, autenticación, etc.) lo eliges tú.
| Tarea | Con http nativo (Node) | Con Express |
|---|---|---|
| Crear servidor | ~10 líneas con createServer | 1 línea: const app = express(); |
| Routing por URL | if/else if/else sobre req.url | app.get('/ruta', handler) |
| Routing por método HTTP | switch sobre req.method | app.get(), app.post(), app.put() separados |
| Middleware | Manual: llamar funciones en orden | app.use(middleware) - encadena solo |
| Parsear JSON del body | Manual con buffer + JSON.parse | app.use(express.json()) - 1 línea |
| Manejo de errores | try/catch manual en cada ruta | Middleware centralizado con (err, req, res, next) |
El administrador aún no ha insertado un video para esta sección.
2.7.2 Tu primer servidor Express
Crear un servidor con Express es tan simple como: importar, instanciar, definir rutas, escuchar. En 5 líneas tienes un servidor funcionando. Las rutas se definen con app.METHOD(path, handler).
// app.js: tu primer servidor Express
import express from 'express';
const app = express();
const PORT = 3000;
// Middleware: parsear JSON del body (necesario para POST)
app.use(express.json());
// RUTAS
app.get('/', (req, res) => {
res.json({ mensaje: 'Hola desde Express!' });
});
app.get('/api/usuarios', (req, res) => {
res.json([
{ id: 1, nombre: 'Ana' },
{ id: 2, nombre: 'Luis' },
]);
});
app.post('/api/usuarios', (req, res) => {
const { nombre } = req.body;
res.status(201).json({ id: 3, nombre });
});
// Iniciar servidor
app.listen(PORT, () => {
console.log(`Servidor en http://localhost:${PORT}`);
});Servidor Express básico en 15 líneas
El administrador aún no ha insertado un video para esta sección.
2.7.3 Routing: app.get, app.post, app.use
Express organiza las rutas con métodos que coinciden con los verbos HTTP: app.get para leer, app.post para crear, app.put para actualizar, app.delete para eliminar. Cada ruta recibe un handler con (req, res). También puedes agrupar rutas con Router, separando tu API en módulos.
| Método HTTP | Operación CRUD | Método Express |
|---|---|---|
| GET | Read (leer) | app.get('/ruta', handler) |
| POST | Create (crear) | app.post('/ruta', handler) |
| PUT / PATCH | Update (actualizar) | app.put('/ruta', handler) |
| DELETE | Delete (eliminar) | app.delete('/ruta', handler) |
| ANY | Cualquier método | app.all('/ruta', handler) |
// routes/usuarios.js: rutas agrupadas con Router
import { Router } from 'express';
const router = Router();
// Rutas: relativas al prefijo /api/usuarios
router.get('/', (req, res) => res.json([]));
router.get('/:id', (req, res) => res.json({ id: req.params.id }));
router.post('/', (req, res) => res.status(201).json({ id: 1 }));
router.put('/:id', (req, res) => res.json({ id: req.params.id, ...req.body }));
router.delete('/:id', (req, res) => res.status(204).send());
export default router;
// app.js: monta el router con un prefijo
import usuariosRouter from './routes/usuarios.js';
app.use('/api/usuarios', usuariosRouter);
// Ahora:
// GET /api/usuarios -> listar
// GET /api/usuarios/5 -> ver uno
// POST /api/usuarios -> crear
// PUT /api/usuarios/5 -> actualizar
// DELETE /api/usuarios/5 -> eliminarRouting modular con Router y prefijos
El administrador aún no ha insertado un video para esta sección.
2.7.4 Middleware: el concepto clave de Express
Un middleware es una función que se ejecuta ENTRE la petición y la respuesta. Pueden modificar req/res, terminar la petición (con res.send), o pasar al siguiente middleware con next(). Es el patrón que hace a Express tan extensible y elegante.
La anatomía de un middleware
// Un middleware es una función con esta firma:
function miMiddleware(req, res, next) {
// 1. Hacer algo con la petición (logging, auth, parse, etc.)
console.log(`${req.method} ${req.url}`);
// 2a. O TERMINAR la petición (enviar respuesta)
// res.status(401).json({ error: 'No autorizado' });
// 2b. O PASAR al siguiente middleware con next()
next();
}
// Registrarlo GLOBALMENTE (se ejecuta para TODAS las rutas):
app.use(miMiddleware);
// O solo para rutas específicas:
app.use('/api', miMiddleware);Anatomía de un middleware
Los 5 middlewares más usados en producción
| Middleware | Para qué sirve | Cuándo usarlo |
|---|---|---|
| express.json() | Parsea el body como JSON. | SIEMPRE, al inicio de la app. |
| express.urlencoded() | Parsea formularios HTML. | Si recibes datos de <form>. |
| cors() | Permite peticiones desde otros dominios. | Si tu frontend está en otro dominio. |
| morgan('dev') | Logger HTTP en consola. | En desarrollo. En producción usa 'combined' o Winston. |
| express.static() | Sirve archivos estáticos. | Para servir HTML, CSS, JS, imágenes. |
El administrador aún no ha insertado un video para esta sección.
2.7.5 req y res: leer peticiones, enviar respuestas
Express enriquece los objetos req (request) y res (response) de Node con propiedades y métodos útiles. Conocerlos bien te permite manejar cualquier tipo de petición HTTP sin reinventar la rueda.
| req (request) | Qué contiene | res (response) | Qué hace |
|---|---|---|---|
| req.body | Datos del cuerpo (POST/PUT). Requiere express.json(). | res.json(obj) | Envía JSON con Content-Type correcto. |
| req.params | Parámetros de la URL: /usuarios/:id -> req.params.id. | res.send(text) | Envía texto plano. |
| req.query | Query string: /buscar?q=php -> req.query.q. | res.status(404) | Cambia el código de estado. |
| req.headers | Headers HTTP (Authorization, Content-Type, etc.). | res.sendFile(path) | Envía un archivo. |
| req.method | GET, POST, PUT, DELETE, etc. | res.redirect(url) | Redirige (302). |
| req.url / req.path | URL completa / path. | res.download(path) | Fuerza descarga de archivo. |
El administrador aún no ha insertado un video para esta sección.
2.7.6 Manejo de errores profesional
Express tiene un mecanismo especial para errores: cuando pasas un error a next(err), salta al siguiente middleware de errores. Esto te permite tener UN SOLO lugar donde manejar todos los errores de tu app, en vez de try/catch en cada ruta.
El patrón moderno: async/await con wrapper
// utils/asyncHandler.js: wrapper que captura errores async
const asyncHandler = (fn) => (req, res, next) => {
Promise.resolve(fn(req, res, next)).catch(next);
};
// routes/usuarios.js: uso limpio
router.get('/', asyncHandler(async (req, res) => {
const usuarios = await db.query('SELECT * FROM usuarios');
res.json(usuarios);
}));
router.post('/', asyncHandler(async (req, res) => {
if (!req.body.email) {
const error = new Error('Email requerido');
error.status = 400;
throw error;
}
const usuario = await db.query('INSERT INTO usuarios ...');
res.status(201).json(usuario);
}));
// Middleware de errores (SIEMPRE al final, con 4 parámetros)
app.use((err, req, res, next) => {
console.error(err.stack);
const status = err.status || 500;
res.status(status).json({
error: err.message || 'Error interno del servidor',
});
});Manejo de errores con asyncHandler
El administrador aún no ha insertado un video para esta sección.
📚 Contenido ampliado
Material adicional, referencias externas verificadas y ejemplos extendidos.
🤖 AI Mission
Express se aprende construyendo APIs reales, no leyendo tutoriales.
Misión: Construye una API REST completa de gestión de libros con Express. Implementa: GET /libros (listar), GET /libros/:id, POST /libros, PUT /libros/:id, DELETE /libros/:id. Usa un array en memoria como 'base de datos' (luego lo cambias por MongoDB). Pídele a la IA que sugiera 2 mejoras. Anota en tu cuaderno: ¿qué parte fue la más difícil?
Pasos sugeridos
- Crea carpeta 'api-express-libros'. npm init -y. Configura 'type': 'module'.
- Instala: npm install express. Y nodemon como devDep: npm install -D nodemon.
- Crea server.js con Express. Configura el middleware express.json().
- Crea un array en memoria con 3 libros: const libros = [{ id: 1, titulo: 'El Quijote', ... }]
- Implementa las 5 rutas CRUD: GET /, GET /:id, POST /, PUT /:id, DELETE /:id.
- Usa el wrapper asyncHandler para manejar errores async.
- Agrega un middleware de errores al final.
- Prueba con curl: listar, ver uno, crear, actualizar, eliminar.
- Pídele a la IA: 'Tengo esta API Express de libros. Sugiere 2 mejoras: validación, búsqueda, o paginación. NO me des código, dime QUÉ agregar y POR QUÉ.'
- Aplica 2 mejoras. Vuelve a probar con curl.
- Anota en tu cuaderno: 3 cosas que aprendiste construyendo esta API que ningún tutorial te enseñó.
📓 Entregable: Capturas de las 5 rutas funcionando con curl, código de server.js, y media página de cuaderno con tu reflexión.
🚫 Errores típicos de razonamiento
Por qué: Sin express.json(), req.body viene undefined en los POST. El middleware parsea el body de las peticiones con Content-Type: application/json. Siempre va al inicio de tu app: app.use(express.json()). Es el error #1 de principiantes con Express.
Por qué: Express 4 NO captura errores en handlers async automáticamente. Si tu handler hace throw new Error() o tiene una await que falla, el error NO se propaga al middleware de errores, sino que se convierte en una excepción no capturada que mata el proceso. Solución: usa el wrapper asyncHandler O usa try/catch en cada handler. Express 5 (en desarrollo) lo arreglará nativamente.
Por qué: El middleware de errores de Express se reconoce por tener 4 parámetros: (err, req, res, next). Si pones 3, Express lo trata como middleware normal y NUNCA lo llama para errores. Es un detalle que mucha gente olvida. La firma: app.use((err, req, res, next) => {...}), 4 parámetros SIEMPRE.
Por qué: Si pones todas tus rutas en app.js, termina con 2000 líneas imposibles de mantener. La solución: usa Router para agrupar rutas por entidad (usuarios, productos, pedidos). Cada archivo de rutas tiene sus propias rutas, y app.js los monta con app.use(). Es el patrón profesional y la base de cualquier API mantenible.
Por qué: Si tu middleware de errores hace res.status(500).json({ error: err.message, stack: err.stack }), estás REVELANDO tu stack trace al usuario, lo cual es un riesgo de seguridad (muestra rutas de archivos internos, versiones de paquetes, etc.). En producción: solo el mensaje genérico, y el stack va a error_log del servidor.
🧪 Laboratorio práctico
Express se aprende haciendo: cada ruta que agregas es una habilidad nueva.
Laboratorio: API REST completa de gestión de libros con Express
Objetivo: Construir una API REST profesional con Express: 5 rutas CRUD, middleware de errores, validación básica, y servirla con nodemon en desarrollo. Practicarás: routing, Router, middleware, async/await, y manejo de errores.
Pasos
- Crea 'api-libros-express'. npm init -y. Configura 'type': 'module'.
- Instala express y nodemon: npm install express + npm install -D nodemon.
- Configura script 'dev' en package.json: 'dev': 'nodemon app.js'.
- Crea data/libros.js con array de 5 libros exportado.
- Crea middleware/asyncHandler.js (el wrapper).
- Crea routes/libros.js con las 5 rutas CRUD usando Router.
- Crea app.js: importa express, configura middlewares (express.json, morgan dev), monta el router con prefijo /api/libros, agrega middleware de errores.
- Prueba con curl o Thunder Client (extensión de VS Code): listar, ver uno, crear, actualizar, eliminar.
- Agrega validación: si el POST no trae titulo o autor, devuelve 400 con mensaje claro.
- Agrega búsqueda: GET /api/libros?autor=Cervantes filtra por autor.
- Inicia con npm run dev. Verifica que nodemon recarga al guardar.
- Haz commit: 'feat: API REST de libros con Express, Router, asyncHandler y validación'.
📓 Entregable: Capturas de las 5 rutas funcionando con curl/Thunder, código de los 4 archivos JS, y commit en Git.