Express.js es un framework minimalista para Node.js que te permite crear APIs REST de forma rápida, organizada y con muy poco código.
El problema de construir sin herramientas
Imagina que trabajas en el equipo de tecnología de Liverpool. Tu líder te pide crear un servicio que regrese la información de productos desde una base de datos. Sin ningún framework, escribirías decenas de líneas solo para interpretar la URL, leer el método HTTP y armar la respuesta. Cada ruta nueva duplicaría ese esfuerzo. Express.js existe exactamente para resolver ese problema.
Con Express, defines una ruta en una sola línea. Manejas parámetros con una sintaxis clara. Envías respuestas JSON sin código repetitivo. Es el estándar de la industria en Node.js por una razón: funciona.
El Sistema RUTA-MÉTODO-RESPUESTA
Antes de escribir código, entiende el modelo mental detrás de Express. Llámalo el Sistema RUTA-MÉTODO-RESPUESTA. Toda API que construyas en Express sigue este patrón:
- RUTA: La dirección a la que llega la petición (por ejemplo,
/productos). - MÉTODO: La acción HTTP que se usa —
GETpara leer,POSTpara crear,PUTpara actualizar,DELETEpara eliminar. - RESPUESTA: Lo que tu servidor regresa, casi siempre en formato JSON.
Si memorizas este sistema, puedes construir cualquier API. Todo lo demás es detalle.
Instala Express.js en tu proyecto
Primero, crea una carpeta nueva para tu proyecto y entra en ella:
mkdir api-liverpool
cd api-liverpool
npm init -y
npm install express
El comando npm init -y crea tu archivo package.json con valores por defecto. El comando npm install express descarga Express y lo agrega como dependencia. Listo. Ya puedes usarlo.
Tu primera API: el servidor mínimo
Crea un archivo llamado index.js y escribe esto:
const express = require('express');
const app = express();
const PUERTO = 3000;
app.use(express.json());
app.get('/', (req, res) => {
res.json({ mensaje: 'API de Liverpool activa' });
});
app.listen(PUERTO, () => {
console.log(`Servidor corriendo en el puerto ${PUERTO}`);
});
Ejecútalo con node index.js. Abre tu navegador en http://localhost:3000 y verás la respuesta JSON. Eso es una API funcional en menos de 10 líneas.
La línea app.use(express.json()) es importante. Le dice a Express que lea el cuerpo de las peticiones en formato JSON. Sin ella, no podrás leer los datos que envía el cliente en peticiones POST o PUT.
Rutas con parámetros: datos dinámicos
Una API real necesita rutas dinámicas. Por ejemplo, si quieres consultar un producto específico por su ID, usas un parámetro en la ruta:
const productos = [
{ id: 1, nombre: 'Pantalla 55"', precio: 12500 },
{ id: 2, nombre: 'Lavadora automática', precio: 8900 },
{ id: 3, nombre: 'Refrigerador', precio: 15300 }
];
app.get('/productos', (req, res) => {
res.json(productos);
});
app.get('/productos/:id', (req, res) => {
const id = parseInt(req.params.id);
const producto = productos.find(p => p.id === id);
if (!producto) {
return res.status(404).json({ error: 'Producto no encontrado' });
}
res.json(producto);
});
El :id en la ruta es un parámetro dinámico. Express lo captura automáticamente en req.params.id. Si alguien visita /productos/2, obtendrá la información de la lavadora. Si pide un ID que no existe, el servidor responde con un código 404 y un mensaje claro.
Fíjate en el parseInt(). El parámetro llega como texto. Sin convertirlo a número, la comparación con === falla porque "2" !== 2.
Rutas POST: recibir datos del cliente
Ahora supón que Bimbo necesita una API para registrar pedidos nuevos. Usas el método POST:
let pedidos = [];
let siguienteId = 1;
app.post('/pedidos', (req, res) => {
const { producto, cantidad, precioUnitario } = req.body;
if (!producto || !cantidad || !precioUnitario) {
return res.status(400).json({ error: 'Faltan datos obligatorios' });
}
const total = cantidad * precioUnitario;
const nuevoPedido = {
id: siguienteId++,
producto,
cantidad,
precioUnitario,
total
};
pedidos.push(nuevoPedido);
res.status(201).json({
mensaje: 'Pedido registrado',
pedido: nuevoPedido
});
});
Ejemplo de petición POST con los datos:
{
"producto": "Pan de caja",
"cantidad": 100,
"precioUnitario": 35
}
La respuesta que regresa el servidor:
{
"mensaje": "Pedido registrado",
"pedido": {
"id": 1,
"producto": "Pan de caja",
"cantidad": 100,
"precioUnitario": 35,
"total": 3500
}
}
El código 201 significa "recurso creado con éxito". Es más preciso que un 200 genérico. Usar los códigos HTTP correctos hace tu API más profesional y más fácil de consumir.
Query strings: filtros opcionales
Además de los parámetros en la ruta, Express maneja los query strings — esos filtros que van después del ? en la URL. Por ejemplo: /productos?categoria=electronica.
app.get('/buscar', (req, res) => {
const { nombre } = req.query;
if (!nombre) {
return res.status(400).json({ error: 'Escribe un término de búsqueda' });
}
const resultados = productos.filter(p =>
p.nombre.toLowerCase().includes(nombre.toLowerCase())
);
res.json({
total: resultados.length,
resultados
});
});
Si alguien visita /buscar?nombre=lava, la API regresa todos los productos que contengan "lava" en el nombre. Express captura los query strings automáticamente en req.query.
Organiza tus rutas con Router
Cuando tu API crece, meter todas las rutas en index.js se vuelve un caos. Express tiene una solución: el objeto Router. Te permite separar rutas en archivos distintos.
Crea un archivo rutas/productos.js:
const express = require('express');
const router = express.Router();
const productos = [
{ id: 1, nombre: 'Pantalla 55"', precio: 12500 },
{ id: 2, nombre: 'Lavadora automática', precio: 8900 }
];
router.get('/', (req, res) => {
res.json(productos);
});
router.get('/:id', (req, res) => {
const id = parseInt(req.params.id);
const producto = productos.find(p => p.id === id);
if (!producto) return res.status(404).json({ error: 'No encontrado' });
res.json(producto);
});
module.exports = router;
Luego en tu index.js:
const rutasProductos = require('./rutas/productos');
app.use('/productos', rutasProductos);
Ahora todas las rutas de productos viven en su propio archivo. Si mañana FEMSA te pide agregar rutas de empleados, creas rutas/empleados.js y listo. Tu código escala sin volverse ilegible.
Errores comunes al usar Express
Esto lo ve todo desarrollador que empieza con Express. Aprende de los errores más frecuentes ahora.
1. Olvidar app.use(express.json())
Sin esta línea, req.body siempre estará vacío. Tus rutas POST y PUT no recibirán ningún dato. Ponla siempre al inicio, antes de definir cualquier ruta.
2. No convertir req.params.id a número
Los parámetros de ruta siempre llegan como texto. Si tu ID en el arreglo es un número y comparas con ===, nunca va a coincidir. Usa parseInt() o Number() antes de comparar.
3. No regresar después de una respuesta de error Este error provoca un crash del servidor:
// MAL — el código sigue ejecutándose después del error
if (!producto) {
res.status(404).json({ error: 'No encontrado' });
}
res.json(producto); // Esto falla si producto es undefined
// BIEN — usa return para detener la ejecución
if (!producto) {
return res.status(404).json({ error: 'No encontrado' });
}
res.json(producto);
4. Ignorar los códigos de estado HTTP
No todo es 200. Usa 201 al crear, 400 para datos inválidos, 404 cuando algo no existe y 500 para errores internos. Tus compañeros de equipo y las apps que consuman tu API lo agradecerán.
5. Poner toda la lógica dentro del handler Si tu función de ruta tiene 50 líneas, algo está mal. Extrae la lógica a funciones separadas o servicios. El handler solo debe orquestar: recibir, procesar y responder.
El patrón que usarás en todo proyecto real
En cualquier empresa de tecnología en México —desde una startup en CDMX hasta el equipo digital de Mercado Libre— verás la misma estructura base:
index.js: configura Express y arranca el servidor.rutas/: contiene un archivo por cada recurso.controladores/: contiene la lógica de negocio.modelos/: define la estructura de los datos.
No necesitas implementar todo esto desde el día uno. Pero saber que existe te ayuda a tomar mejores decisiones conforme tu proyecto crece.
Express.js no solo simplifica el código: te da una estructura que tu equipo puede entender, mantener y escalar sin caos.