🚂 2.7 · Express.js: APIs profesionales en minutos

⏱ 6h 00min ⚡ 100 XP 🏅 Profesional Junior 📖 Backend FullStack
"Express no es un framework pesado: es una capa fina sobre Node que te da superpoderes."

🎯 Objetivo del tema

Al terminar este tema serás capaz de: Al terminar este tema serás capaz de crear un servidor Express con routing profesional, middleware (logger, autenticación, CORS), manejo de errores, y servir una API REST básica. Express es el framework más usado de Node.js y la base de casi todo: APIs, microservicios, backends de React, etc.
🎬
Video del instructor

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.

1. Qué es Express y por qué usarlo

El framework minimalista que te ahorra 200 líneas de boilerplate.

2. Tu primer servidor Express

5 líneas para tener un servidor con routing básico.

3. Routing: app.get, app.post, app.use

Cómo organizar las rutas de tu API de forma limpia.

4. Middleware: el concepto clave de Express

Funciones que se ejecutan en cadena: logger, auth, parse, etc.

5. req y res: leer peticiones, enviar respuestas

Los objetos que Express te da en cada handler.

6. Manejo de errores profesional

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ú.

TareaCon http nativo (Node)Con Express
Crear servidor~10 líneas con createServer1 línea: const app = express();
Routing por URLif/else if/else sobre req.urlapp.get('/ruta', handler)
Routing por método HTTPswitch sobre req.methodapp.get(), app.post(), app.put() separados
MiddlewareManual: llamar funciones en ordenapp.use(middleware) - encadena solo
Parsear JSON del bodyManual con buffer + JSON.parseapp.use(express.json()) - 1 línea
Manejo de errorestry/catch manual en cada rutaMiddleware centralizado con (err, req, res, next)
⭐ Express es el estándar: Express no es el ÚNICO framework de Node. Hay otros: Koa (más moderno, del mismo creador), Fastify (más rápido), NestJS (más opinionated, estilo Angular). Pero Express sigue siendo el MÁS USADO y el que más recursos, tutoriales y soporte tiene. Domina Express primero; los demás se aprenden rápido.
🎬
Video del instructor

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

⭐ express.json() es esencial: app.use(express.json()) es FUNDAMENTAL: sin él, req.body viene undefined en los POST. Este middleware parsea el body de las peticiones con Content-Type: application/json y lo deja disponible como req.body. Es uno de los middlewares más usados y siempre va al inicio de tu app.
🎬
Video del instructor

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 HTTPOperación CRUDMétodo Express
GETRead (leer)app.get('/ruta', handler)
POSTCreate (crear)app.post('/ruta', handler)
PUT / PATCHUpdate (actualizar)app.put('/ruta', handler)
DELETEDelete (eliminar)app.delete('/ruta', handler)
ANYCualquier métodoapp.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     -> eliminar

Routing modular con Router y prefijos

⭐ Router > if/else gigante: Router + app.use() es el patrón PROFESIONAL: cada entidad (usuarios, productos, pedidos) tiene su propio archivo de rutas. Tu app.js queda limpio y solo orquesta. Es la diferencia entre un proyecto mantenible y un monolito de 2000 líneas en un solo archivo.
🎬
Video del instructor

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.

📷 Imagen referencial: Pipeline de middleware: petición -> logger -> CORS -> parse JSON -> auth -> ruta -> respuesta.

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

MiddlewarePara qué sirveCuá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 orden importa: El ORDEN de los middlewares importa MUCHO. Si pones express.json() DESPUÉS de una ruta que lee req.body, no funcionará. Si pones el logger DESPUÉS de las rutas, no verás las peticiones 404. La regla general: middlewares globales primero (logger, parse, CORS), luego rutas, luego middleware de errores al final.
🎬
Video del instructor

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é contieneres (response)Qué hace
req.bodyDatos del cuerpo (POST/PUT). Requiere express.json().res.json(obj)Envía JSON con Content-Type correcto.
req.paramsParámetros de la URL: /usuarios/:id -> req.params.id.res.send(text)Envía texto plano.
req.queryQuery string: /buscar?q=php -> req.query.q.res.status(404)Cambia el código de estado.
req.headersHeaders HTTP (Authorization, Content-Type, etc.).res.sendFile(path)Envía un archivo.
req.methodGET, POST, PUT, DELETE, etc.res.redirect(url)Redirige (302).
req.url / req.pathURL completa / path.res.download(path)Fuerza descarga de archivo.
⭐ status() antes de send(): El orden de res.json() y res.status() IMPORTA: res.status(404).json({...}) funciona. res.json({...}).status(404) NO funciona (status no se encadena con json en Express). La regla: status() primero, luego send().
🎬
Video del instructor

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

⭐ 4 parámetros: la firma clave: El middleware de errores tiene 4 parámetros (err, req, res, next). Express lo reconoce por tener 4 parámetros: si tiene 3, lo trata como middleware normal. Por eso la firma es: app.use((err, req, res, next) => {...}). Es un detalle que mucha gente olvida y por eso sus middlewares de error nunca se llaman.
🎬
Video del instructor

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

  1. Crea carpeta 'api-express-libros'. npm init -y. Configura 'type': 'module'.
  2. Instala: npm install express. Y nodemon como devDep: npm install -D nodemon.
  3. Crea server.js con Express. Configura el middleware express.json().
  4. Crea un array en memoria con 3 libros: const libros = [{ id: 1, titulo: 'El Quijote', ... }]
  5. Implementa las 5 rutas CRUD: GET /, GET /:id, POST /, PUT /:id, DELETE /:id.
  6. Usa el wrapper asyncHandler para manejar errores async.
  7. Agrega un middleware de errores al final.
  8. Prueba con curl: listar, ver uno, crear, actualizar, eliminar.
  9. 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É.'
  10. Aplica 2 mejoras. Vuelve a probar con curl.
  11. 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

Error 1: Olvidar express.json() y obtener req.body undefined en POST.
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.
Error 2: No usar try/catch en handlers async.
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.
Error 3: Poner el middleware de errores con 3 parámetros en vez de 4.
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.
Error 4: No usar Router y poner todas las rutas en app.js.
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.
Error 5: Devolver datos sensibles en las respuestas de error.
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

  1. Crea 'api-libros-express'. npm init -y. Configura 'type': 'module'.
  2. Instala express y nodemon: npm install express + npm install -D nodemon.
  3. Configura script 'dev' en package.json: 'dev': 'nodemon app.js'.
  4. Crea data/libros.js con array de 5 libros exportado.
  5. Crea middleware/asyncHandler.js (el wrapper).
  6. Crea routes/libros.js con las 5 rutas CRUD usando Router.
  7. Crea app.js: importa express, configura middlewares (express.json, morgan dev), monta el router con prefijo /api/libros, agrega middleware de errores.
  8. Prueba con curl o Thunder Client (extensión de VS Code): listar, ver uno, crear, actualizar, eliminar.
  9. Agrega validación: si el POST no trae titulo o autor, devuelve 400 con mensaje claro.
  10. Agrega búsqueda: GET /api/libros?autor=Cervantes filtra por autor.
  11. Inicia con npm run dev. Verifica que nodemon recarga al guardar.
  12. 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.

📓 Tu cuaderno: Anota pseudocódigo, diagramas, errores que encontraste y respuestas a "explica sin código". La escritura manual refuerza tu razonamiento. Tu profesor puede pedirte que subas fotos de páginas específicas.