Skip to content

Backend - Servidor Web y API REST con Node.js

🚀 Clases en Vivo — Inicio: Domingo 6 de Septiembre ($200 MXN / clase). Aprende a programar desde cero con acompañamiento directo y construye el proyecto ShortURL.

En la Lección 6: Frontend - HTML, CSS y DOM (L6) construimos una interfaz gráfica atractiva y responsiva para nuestro proyecto ShortURL.

Sin embargo, hasta el momento los enlaces se generaban de forma simulada en la memoria del navegador. Si otra persona intentaba abrir el enlace corto desde su teléfono, ¡la página no existía! Para que una aplicación web funcione globalmente, necesitamos un servidor central que atienda peticiones día y noche, procese los datos y redirija a los visitantes: el Backend.

En esta sesión intensiva de 4 horas, utilizaremos Node.js y Express para crear nuestro primer servidor web profesional, implementaremos una API REST con endpoints POST y GET, programaremos redirecciones HTTP automáticas y conectaremos la interfaz gráfica con el servidor utilizando fetch().


🗺️ Estructura de la Sesión

Cada una de nuestras sesiones semanales sigue una metodología pedagógica dividida en 5 fases:

Estructura de la Sesión
├── ☕ Fase 1: Revisión del Tema Anterior y Conclusiones
├── 🎯 Fase 2: Introducción al Tema y Fundamentos
├── 💻 Fase 3: Práctica Asistida en Vivo
├── 🗣️ Fase 4: Exposición, Debate y Debugging
└── 🏠 Fase 5: Reto Semanal y Práctica en Casa

☕ Fase 1: Revisión del Tema Anterior y Conclusiones

Iniciamos la sesión analizando la interfaz creada la semana anterior y entendiendo por qué el navegador necesita un servidor.

1. Puesta en Común del Reto de la Lección 6

En la lección previa construimos el Frontend con HTML, CSS Flexbox y JavaScript para el DOM:

  • Discusión en grupo: ¿Cómo implementaste el cambio de color rojo/verde en el input de texto?
  • ¿Pudiste probar el botón de copiar al portapapeles y pegar el enlace en otra pestaña?
  • ¿Qué ocurrió cuando intentaste compartir ese enlace corto con un compañero de clase? (Descubrieron que no cargaba porque nadie estaba sirviendo esa URL en la red).

2. El Puente Conceptual: El Servidor Web como Restaurante

En el mundo web, la comunicación sigue el modelo del Restaurante:

  • El Cliente (Frontend): Eres tú sentado en la mesa revisando el menú.
  • El Servidor (Backend): Es la cocina donde se preparan los pedidos y se resguardan las recetas.
  • La API (El Camarero / Mesero): Es el mensajero formal que lleva tu pedido a la cocina y regresa con tu platillo listo.

Hoy construiremos esa cocina con Node.js y programaremos al camarero con Express para que atienda a los clientes de ShortURL.


🎯 Fase 2: Introducción al Tema y Fundamentos Teóricos

Analicemos qué es Node.js, cómo funciona el protocolo HTTP y la anatomía de los endpoints.


1. ¿Qué es Node.js y por qué revolucionó el desarrollo?

Originalmente, JavaScript solo podía ejecutarse dentro de navegadores web (Chrome, Firefox, Safari). En 2009, Ryan Dahl tomó el motor V8 de Google Chrome y lo adaptó para que pudiera ejecutarse directamente en el sistema operativo de cualquier computadora.

Con Node.js, JavaScript se convirtió en un lenguaje universal: ahora podemos usar el mismo lenguaje para diseñar botones en el navegador y para crear servidores de alto rendimiento en la nube.


2. El Protocolo HTTP: Métodos y Códigos de Estado

Cada vez que un navegador interactúa con un servidor, intercambian mensajes mediante el protocolo HTTP (HyperText Transfer Protocol):

Los 2 Métodos Principales:

  • GET (Obtener / Visitar): Se usa para solicitar información o visitar una página (ej. cuando escribes short.ly/a8B9x en la barra de direcciones).
  • POST (Enviar / Crear): Se usa para enviar información al servidor en un paquete oculto llamado Body (ej. cuando envías el formulario con la URL larga).

Códigos de Estado HTTP Fundamentales:

  • 200 OK: La petición fue exitosa y se envían los datos solicitados.
  • 201 Created: El recurso fue creado exitosamente en el servidor.
  • 302 Found (Redirección): Le ordena al navegador: “El recurso que buscas está en esta otra dirección web, viaja hacia allá de inmediato”.
  • 400 Bad Request: El cliente envió datos inválidos o incompletos.
  • 404 Not Found: El recurso solicitado no existe en el servidor.

3. ¿Qué es una API REST y qué es un Endpoint?

Una API REST es una colección de “ventanillas de atención” (Endpoints) que el servidor expone para que el Frontend solicite operaciones:

Rutas de la API de ShortURL
├── POST /api/acortar ──► Recibe { urlOriginal } ──► Devuelve { urlCorta, codigo } (Código 201)
├── GET /:codigo ──► Busca código en memoria ──► Redirige a la URL original (Código 302)
└── GET / ──► Entrega el index.html del Frontend (Código 200)

🔍 Experimento en Vivo: Haciendo peticiones HTTP con fetch()

Vamos a consumir una API real pública desde la consola de nuestro navegador:

  1. Abre la consola de tu navegador (F12).
  2. Ejecuta este código para consultar datos en vivo de una API pública:
    fetch("https://jsonplaceholder.typicode.com/todos/1")
    .then(respuesta => respuesta.json())
    .then(datos => {
    console.log("📦 Datos recibidos del servidor remoto:", datos);
    console.log("Título de la tarea:", datos.title);
    });
  3. Observa el resultado: Tu navegador viajó a un servidor en internet, descargó un objeto JSON y te lo entregó listo en JavaScript. ¡Esa misma comunicación haremos entre nuestro frontend y nuestro backend!

💻 Fase 3: Práctica Asistida en Vivo

Crearemos el servidor backend completo de ShortURL en Node.js.


🧩 Reto 1: Inicialización y Servidor Base (server.js)

Objetivo: Configurar el servidor Express en el puerto 3000 y servir la carpeta estática /public.

Crea un archivo llamado server.js en la raíz de tu proyecto:

server.js
// 1. Importamos la librería Express
const express = require("express");
const app = express();
const PUERTO = 3000;
// 2. Middleware para que Express entienda peticiones con formato JSON
app.use(express.json());
// 3. Servir automáticamente los archivos de la interfaz (HTML, CSS, JS)
app.use(express.static("public"));
// 4. Base de datos temporal en memoria
const baseDeDatos = [];
// 5. Encendemos el servidor para escuchar peticiones
app.listen(PUERTO, () => {
console.log(`🚀 Servidor ShortURL ejecutándose en: http://localhost:${PUERTO}`);
});

🧩 Reto 2: Endpoint para Acortar Enlaces (POST /api/acortar)

Objetivo: Recibir una URL larga en el cuerpo de la petición, validarla, generar un código único y responder con JSON.

Agrega este bloque a tu server.js:

server.js (Continuación)
// Función generadora de códigos cortos de 6 caracteres
function generarCodigo(longitud = 6) {
const caracteres = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
let codigo = "";
for (let i = 0; i < longitud; i++) {
codigo += caracteres[Math.floor(Math.random() * caracteres.length)];
}
return codigo;
}
// Endpoint POST: Crear enlace corto
app.post("/api/acortar", (req, res) => {
const { urlOriginal } = req.body;
// Validación de seguridad básica
if (!urlOriginal || !urlOriginal.startsWith("http")) {
return res.status(400).json({
error: "La URL es inválida. Debe comenzar con http:// o https://"
});
}
// Generamos el código y guardamos la ficha
const codigo = generarCodigo();
const nuevoRegistro = {
id: Date.now(),
urlOriginal: urlOriginal,
codigoCorto: codigo,
clics: 0,
fechaCreacion: new Date().toISOString()
};
baseDeDatos.push(nuevoRegistro);
console.log(`[POST] Enlace creado: ${codigo} -> ${urlOriginal}`);
// Respondemos al cliente con código HTTP 201 (Created)
res.status(201).json({
exito: true,
codigo: codigo,
urlCorta: `http://localhost:${PUERTO}/${codigo}`,
urlOriginal: urlOriginal
});
});

🧩 Reto 3: Endpoint de Redirección Automática (GET /:codigo)

Objetivo: Atender la visita del usuario, buscar el enlace en la base de datos, sumar el clic y redirigir al sitio original.

Agrega la ruta de redirección en server.js:

server.js (Continuación)
// Endpoint GET dinámico: Redirigir según el código
app.get("/:codigo", (req, res) => {
const codigoBuscado = req.params.codigo;
// Buscamos si el código existe en nuestra memoria
const enlace = baseDeDatos.find(item => item.codigoCorto === codigoBuscado);
if (!enlace) {
// Si no existe, enviamos código HTTP 404 (Not Found)
return res.status(404).send(`
<h1 style="font-family: sans-serif; text-align: center; margin-top: 50px;">
❌ Error 404: Enlace corto no encontrado
</h1>
<p style="text-align: center;"><a href="/">Volver a ShortURL</a></p>
`);
}
// Incrementamos el contador de visitas
enlace.clics++;
console.log(`[GET] Redirigiendo ${codigoBuscado} a ${enlace.urlOriginal} (Clics: ${enlace.clics})`);
// ¡Redirección mágica de Express!
res.redirect(enlace.urlOriginal);
});

🧩 Reto 4: Conectando el Frontend con el Servidor (app.js)

Objetivo: Modificar el app.js de la Lección 6 para que envíe los datos reales al Backend usando fetch().

Abre public/app.js y actualiza la lógica del formulario:

public/app.js
const formulario = document.getElementById("form-acortar");
const inputUrl = document.getElementById("input-url");
const seccionResultado = document.getElementById("seccion-resultado");
const btnAcortar = document.getElementById("btn-acortar");
formulario.addEventListener("submit", async function(evento) {
evento.preventDefault();
const urlAEnviar = inputUrl.value.trim();
btnAcortar.disabled = true;
btnAcortar.innerText = "⏳ Acortando...";
try {
// Enviamos la petición POST al backend
const respuesta = await fetch("/api/acortar", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ urlOriginal: urlAEnviar })
});
const datos = await respuesta.json();
if (!respuesta.ok) {
throw new Error(datos.error || "Ocurrió un error en el servidor");
}
// Renderizamos la URL corta real entregada por Node.js
renderizarResultado(datos.urlCorta, datos.urlOriginal);
inputUrl.value = "";
} catch (error) {
alert("❌ Error: " + error.message);
} finally {
btnAcortar.disabled = false;
btnAcortar.innerText = "Acortar Enlace";
}
});

🗣️ Fase 4: Exposición de Resultados, Debate y Debugging

Arrancamos el servidor en la terminal (node server.js), abrimos http://localhost:3000 en el navegador y probamos acortar enlaces reales.

🐞 Las 4 Trampas Clásicas de Backend

1. Olvidar app.use(express.json())

  • El síntoma: req.body llega como undefined y el servidor lanza TypeError: Cannot destructure property 'urlOriginal' of 'req.body'.
  • La causa: Por defecto, Express no interpreta el formato JSON a menos que actives su middleware analizador.
  • La solución: Asegúrate de incluir app.use(express.json()); antes de definir cualquier ruta.

2. Error listen EADDRINUSE: address already in use :::3000

  • La causa: Ya tienes otra ventana o proceso ejecutando un servidor en el puerto 3000.
  • La solución: Cierra el proceso anterior en la terminal (Ctrl + C) o cambia el número de puerto a 3001 o 4000.

3. Olvidar enviar una respuesta (res.json() o res.send())

  • El síntoma: El navegador se queda con el círculo de carga dando vueltas eternamente hasta que se agota el tiempo (Timeout).
  • La causa: Toda petición HTTP necesita una respuesta explícita del servidor para cerrar el ciclo de comunicación.

4. Confundir req.params con req.body

  • Regla de oro: req.params lee variables que vienen escritas en la propia URL (como /:codigo), mientras que req.body lee los datos enviados dentro de una petición POST.

🏠 Fase 5: Definición de Práctica en Casa / Reto Semanal

Crearás un endpoint de analíticas para consultar el rendimiento de los enlaces.

🏆 Proyecto Semanal: “El Endpoint de Métricas de ShortURL”

Descripción del Problema: Los usuarios y creadores de contenido quieren saber cuántas veces se ha hecho clic en sus enlaces acortados.

Especificaciones Técnicas a Implementar:

  1. Nuevo Endpoint GET /api/metricas/:codigo:

    • Crea una nueva ruta en server.js que reciba el código en los parámetros de la URL (req.params.codigo).
    • Busca el enlace en baseDeDatos.
    • Si no existe, responde con código HTTP 404 y un objeto JSON:
      { "error": "El enlace no existe en los registros" }
    • Si existe, responde con código HTTP 200 y el reporte completo:
      {
      "codigo": "x9K2p1",
      "urlOriginal": "https://developer.mozilla.org",
      "clicsTotales": 8,
      "fechaCreacion": "2026-08-18T12:00:00.000Z"
      }
  2. Prueba de Funcionamiento:

    • Acorta un enlace desde la página web.
    • Haz clic en el enlace corto 3 o 4 veces en distintas pestañas.
    • Abre http://localhost:3000/api/metricas/TU_CODIGO en tu navegador y comprueba que el contador clicsTotales refleje exactamente las visitas realizadas.

📚 Recursos y Videos Recomendados

Para profundizar en Node.js, Express y desarrollo Backend:


🚀 Conclusión y Próximos Pasos

¡Felicidades! Acabas de dar el paso más importante en tu camino como desarrollador Full-Stack: has conectado exitosamente una interfaz visual en el navegador con un servidor web real en Node.js.

Ahora nuestro sistema genera enlaces, atiende peticiones y redirige usuarios en milisegundos. Sin embargo, hay un último eslabón pendiente en nuestro stack: si apagamos la computadora o reiniciamos el servidor Node.js… ¡todos los enlaces guardados en memoria se pierden!

En la próxima sesión construiremos el almacenamiento definitivo: Lección 8: Base de Datos - Persistencia Relacional con SQLite y SQL (L8), donde blindaremos nuestros datos para que permanezcan guardados para siempre.

🚀 Clases en Vivo — Inicio: Domingo 6 de Septiembre ($200 MXN / clase). Aprende a programar desde cero con acompañamiento directo y construye el proyecto ShortURL.