Programación Fullstack:
De Principiante a Experto
Una guía paso a paso desde cero
Autora: Roxana Rolón (ROXDEV)
Licencia de uso (resumen):
Se permite la reproducción y uso docente con atribución a Roxana Rolón (RoxDev) y enlace
oficial. Prohibido subir a plataformas o vender fuera de la página oficial sin autorización por
escrito. Contacto: [Link] | [Link]
Primera edición, Rosario, Santa Fe, Argentina. Año: 2025
Edición y maquetación: RoxDev
Diseño de portada: RoxDev
Dedicatoria
Para Lucas, compañero en la escasez y en la esperanza. Para mis
hijos, Génesis, Lucas y Alüén, fuerza y milagro cotidiano. Para mis padres,
Alejandro y Rosa, y mis hermanos, en especial Romina, mi amiga y
confidente. Para mis sobrinos, con el deseo de que un día se enamoren de
la tecnología. En memoria de mis abuelos, doña Nación Ramírez y don
Alejandro Rolón, pilares de mi vida; y de mi hermana del alma, Jaquelina
Ivón Barrios Dugour, que partió en noviembre de 2024 y vive en mi
corazón.
A todos quienes caminaron conmigo, a la distancia o en línea:
gracias. Los quiero un mundo.
EPÍGRAFE
“La tecnología no es magia: es la persistencia de muchas manos que se niegan a rendirse.”
— Roxana Rolón (RoxDevs)
Prólogo
Si alguna vez te dijeron que la programación es solo para “genios”, que necesitas
matemáticas imposibles o que llegaste tarde, quiero que este libro empiece desarmando
ese mito. Programar no es un don místico. Es aprender a conversar con una lógica clara, a
construir con pasos pequeños, a equivocarte y volver a intentarlo con un poquito más de
información que antes. Y ese camino, créeme, está abierto para ti.
Escribí este libro con la certeza de que enseñar es un acto de amor y de paciencia.
Lo pensé para la persona que mira una pantalla y siente que hay un mundo detrás… pero no
sabe por dónde empezar. Para la madre que aprende de noche, para el joven curioso sin
recursos, para quien cambió de carrera y tiene miedo, para la abuela que quiere entender
qué hacen sus nietos, para quienes trabajan y estudian a la vez, para quien perdió y vuelve a
intentar. Aquí no vas a encontrar puertas cerradas ni jerga que te deje afuera. Aquí vas a
encontrar una mano que te dice: vení, probemos juntas.
Programar es construir puentes. Entre una idea y una solución. Entre un problema
real y una herramienta útil. Entre quien necesita algo y quien puede crearlo. Y como todo
puente, se arma con piezas que encajan: HTML para dar forma, CSS para dar estilo,
JavaScript para dar vida. Después, sumamos React para pensar en componentes; Node y
Express para hablar con el servidor; una base de datos para guardar historias. Paso a paso.
Sin atajos que te pierdan, sin promesas vacías.
Quiero que recuerdes esto desde el primer día: el error no es el enemigo. Es tu
entrenador personal. Cada mensaje rojo en tu consola es una pista. Cada bug es una
pregunta que te enseña a pensar mejor. Te voy a mostrar cómo leer esos mensajes, cómo
buscar respuestas, cómo entender qué pasó. No te voy a pedir fe ciega; te voy a mostrar por
qué funciona lo que funciona. Porque la seguridad no nace de memorizar, sino de
comprender.
Este libro también es una invitación a crear con propósito. No basta con escribir
código que “anda”. Vamos a escribir código que otras personas puedan entender, mantener
y mejorar. Vamos a versionar con Git, a documentar, a probar, a hablar de seguridad con
respeto por los datos de las personas. Vamos a pensar en la accesibilidad para que nadie
quede afuera. Vamos a desplegar y ver tu trabajo en línea, vivo, útil, compartible.
Pero, sobre todo, vamos a celebrar cada logro. El primer “Hola Mundo” es un grito de
independencia. La primera función que te sale sin mirar apuntes es un salto de confianza. El
primer error que resolvés sola es una victoria enorme. Quiero que sientas esa chispa y que la
vuelvas hábito. La programación no te pide perfección: te pide constancia.
Mi promesa como autora y como docente es simple:
- Hablaremos claro. Las definiciones están en español, con ejemplos reales y sin vueltas.
- Practicaremos mucho. Copiarás, ejecutarás, romperás y arreglarás. Esa es la gimnasia que
te hace dev.
- Construiremos algo que importe. Un mini-proyecto que crece capítulo a capítulo hasta
convertirse en una aplicación fullstack funcional.
- Te acompañaré en las dudas. Te daré tips, advertencias y atajos honrados. También te diré
cuándo algo es “suficientemente bueno” para avanzar.
Si venís del miedo, te doy razones. Si venís de la curiosidad, te doy herramientas. Si
venís del cansancio, te doy un método. Y si venís del deseo, te doy un camino.
No sos “tarde”. No sos “menos”. Sos la persona indicada para aprender ahora. Lo
único que te pido es que te regales tres cosas: tiempo, paciencia y permiso para
equivocarte. El resto lo hacemos juntas. Y cuando termines este viaje, quiero que mires tu
primera app en línea y digas: lo hice yo. Con mis manos. Con mi cabeza. Con mi historia.
La tecnología no es magia. Es la persistencia de muchas manos que se niegan a
rendirse. Bienvenida a poner las tuyas en la mesa. Empecemos.
INTRODUCCIÓN
Bienvenida al otro lado de la pantalla.
Si estás leyendo esto, es porque tienes una curiosidad que te pica. Quizás miras las
aplicaciones que usas a diario y te preguntas: "¿Cómo rayos funciona esto?". O quizás
quieres cambiar de carrera, mejorar tus ingresos, o simplemente demostrarte a ti misma que
puedes construir cosas con tus propias manos (y tu teclado).
Te voy a decir la verdad: La programación no es para genios. No necesitas ser una experta
en matemáticas ni tener un coeficiente intelectual de tres cifras. Lo que necesitas es
persistencia y perderle el miedo a equivocarte.
En este libro, no voy a soltarte definiciones de enciclopedia. Vamos a trabajar. Vamos a
ensuciarnos las manos (digitalmente). Te voy a enseñar a configurar tu computadora como
una profesional, a escribir tus primeras líneas de código y a entender por qué escribimos lo
que escribimos.
Empezaremos desde cero absoluto —literalmente, desde cómo instalar los programas— y
terminaremos construyendo una aplicación completa que podrás mostrarle al mundo.
Soy Roxana Rolón, y si yo pude aprender, tú también puedes. Respira profundo, prepárate un
café (o un mate), y empecemos.
Guia de uso
Para quién es
● Personas sin experiencia previa que quieren aprender a programar desde cero.
● Quienes ya tocaron algo de HTML/CSS/JS y desean un camino completo hacia
Fullstack.
● Docentes y formadores que buscan material claro y reutilizable con atribución a la
autora.
Qué necesitas
● Computadora con Windows, macOS o Linux.
● Conexión a Internet.
● Visual Studio Code y [Link] LTS.
● Cuenta en GitHub.
● 45–90 minutos por sesión.
Cómo aprenderás
● Paso a paso: definiciones claras + ejemplo mínimo funcional.
● Código primero: qué escribir, dónde, cómo ejecutar y verificar.
● Errores como guía: leerás la consola y depurarás.
● Mini-proyecto incremental: app que crece capítulo a capítulo.
● Buenas prácticas: accesibilidad, seguridad, control de versiones, pruebas y
despliegue.
Convenciones
● Comandos: $ indica terminal (no escribas el símbolo).
● Rutas de archivos: carpetas y nombres exactos.
● Etiquetas: [TIP], [OJO], [RETO].
● Código: listo para copiar y pegar.
Metodología sugerida
● Lee, ejecuta el ejemplo, modifica algo y observa el resultado.
● Haz los ejercicios; vuelve al ejemplo si te trabas.
● Commit por hito (“capítulo”, “ejercicios”, “feature”).
● Crea un diario de aprendizaje en el README.
● Ritmo: 1 capítulo/semana (o 2 si ya tienes bases).
Estructura de cada capítulo
● Objetivos de aprendizaje
● Mapa del capítulo
● Definiciones clave
● Ejemplo mínimo funcional
● Paso a paso (comandos, archivos, ejecución)
● Errores comunes y soluciones
● Ejercicios
● Mini-proyecto (incremento)
● Cierre (resumen y checklist)
Repositorio y materiales
● GitHub de la autora: [Link]
● Sugerencia: crea “fullstack-desde-cero” y sube cada capítulo en su carpeta.
Licencia de uso (resumen)
● Reproducción y uso docente permitidos con atribución a Roxana Rolón (RoxDev) y
enlace oficial.
● Prohibido subir a plataformas o vender fuera de la página oficial sin autorización por
escrito.
Introducción a la Programación Fullstack
Bienvenido al mundo del desarrollo web. En este libro, no solo aprenderás a escribir código,
sino a construir sistemas completos. Desde la interfaz que toca el usuario hasta la base de
datos que guarda sus secretos, te guiaré paso a paso para convertirte en un desarrollador
Fullstack.
1.1 Qué es Fullstack: front-end, back-end y la visión integral
El término Fullstack se refiere a la capacidad de un desarrollador para moverse con soltura
en las dos áreas principales del desarrollo web: el Front-end y el Back-end.
● Front-end (El lado del cliente): Es todo lo que el usuario ve e interactúa en su
navegador. Se trata de diseño, experiencia de usuario (UX), botones, formularios y
animaciones. Las tecnologías principales aquí son HTML, CSS y JavaScript (y
frameworks como React).
● Back-end (El lado del servidor): Es la lógica que ocurre "detrás de escena". Se
encarga de procesar los datos, autenticar usuarios, conectar con la base de datos y
servir la información que el Front-end necesita. Aquí usaremos [Link].
● La visión integral: Un desarrollador Fullstack no necesariamente es un experto
mundial en ambas áreas, pero entiende cómo se conectan. Sabe que un botón en el
front-end dispara una petición HTTP, que llega al servidor, el cual consulta la base de
datos y devuelve una respuesta. Esa visión global es lo que hace valioso a este
perfil.
1.2 Cómo funciona la web: cliente, servidor, HTTP/HTTPS, JSON y
DOM
Para programar para la web, primero debemos entender su arquitectura básica:
1. Cliente y Servidor: El cliente (tu navegador, como Chrome o Firefox) solicita
información. El servidor (una computadora remota escuchando peticiones) envía
esa información.
2. HTTP/HTTPS: Es el protocolo (el idioma) que usan cliente y servidor para hablar.
● Request (Petición): "Oye servidor, dame la página de inicio".
● Response (Respuesta): "Aquí tienes el código HTML".
3. JSON (JavaScript Object Notation): Es el formato estándar para intercambiar datos
hoy en día. Es ligero y fácil de leer tanto para humanos como para máquinas.
4. json
"nombre": "Roxana",
"rol": "Autora"
5. }
6. DOM (Document Object Model): Cuando el navegador recibe HTML, crea un árbol de
objetos en memoria llamado DOM. JavaScript manipula este árbol para cambiar lo
que ves en pantalla sin necesidad de recargar la página.
1.3 Herramientas esenciales: navegador, VS Code, [Link],
Git/GitHub
Antes de escribir una línea de código, necesitas preparar tu taller:
● Navegador Web: Chrome o Firefox (versiones Developer Edition) son ideales por sus
herramientas de inspección.
● VS Code (Visual Studio Code): El editor de código más popular. Es ligero, potente y
tiene miles de extensiones.
● [Link]: Un entorno de ejecución que nos permite correr JavaScript fuera del
navegador (en el servidor). Debes instalar la versión LTS (Long Term Support).
● Git: Un sistema de control de versiones. Es como una "máquina del tiempo" para tu
código, permitiéndote volver a versiones anteriores si algo se rompe.
● GitHub: Una plataforma en la nube para alojar tus repositorios de Git y compartir tu
código.
1.4 Hola Mundo en el navegador (HTML) y en [Link]
Vamos a hacer el ritual de iniciación de todo programador.
A. En el Navegador (HTML)
Crea un archivo llamado [Link] y escribe:
html
<!DOCTYPE html>
<html>
<body>
<h1>Hola Mundo desde el navegador</h1>
<script>
[Link]("¡Y Hola Mundo desde la consola de JavaScript!");
</script>
</body>
</html>
Ábrelo con tu navegador. Verás el texto en grande. Si presionas F12 y vas a la pestaña
"Console", verás el mensaje del script.
B. En el Servidor ([Link])
Abre tu terminal, crea un archivo llamado [Link] y escribe:
javascript
[Link]("Hola Mundo desde el servidor con [Link]");
Ejecútalo escribiendo en tu terminal: node [Link]. Verás el mensaje impreso
directamente en tu terminal, no en el navegador.
1.5 Primer repositorio en GitHub
Guardar tu trabajo es vital. Sigue estos pasos en tu terminal dentro de la carpeta de tu
proyecto:
1. Inicializa Git: git init
2. Agrega tus archivos: git add .
3. Guarda la versión: git commit -m "Mi primer commit: Hola Mundo"
4. Ve a [Link], crea un nuevo repositorio (vacío) y copia los comandos que te dan
para conectar tu repositorio local con el remoto (usualmente git remote add
origin...).
5. Sube tu código: git push -u origin main
¡Felicidades! Tu código está ahora en la nube.
1.6 Ejercicios y mini-proyecto: página de perfil
Para cerrar este capítulo, vamos a aplicar lo aprendido.
Ejercicio:
1. Instala VS Code y [Link].
2. Crea una cuenta en GitHub.
3. Investiga qué es una extensión de archivo .md (Markdown).
Mini-Proyecto: Tu Página de Perfil (Versión 0.1)
Crea una estructura de carpetas simple. Dentro, crea un [Link].
● Usa etiquetas <h1> para tu nombre.
● Usa etiquetas <p> para una breve biografía.
● Usa una etiqueta <ul> con <li> para listar tus hobbies.
● Sube este proyecto a un nuevo repositorio en GitHub llamado "mi-perfil-fullstack".
Fundamentos de Desarrollo Web
Ahora que entendemos el ecosistema, vamos a ensuciarnos las manos con las "Tres
Grandes" tecnologías de la web: HTML, CSS y JavaScript. Piensa en esto como la
construcción de una casa: HTML es la estructura de concreto, CSS es la pintura y
decoración, y JavaScript es la electricidad y la domótica.
2.1 HTML: estructura y semántica; formularios y accesibilidad
HTML (HyperText Markup Language) no es un lenguaje de programación, es un lenguaje de
marcado. Define qué son las cosas.
Estructura y Semántica
Antiguamente, usábamos <div> para todo. Hoy usamos HTML Semántico. Esto significa
usar etiquetas que describen el contenido. Esto ayuda a Google (SEO) a entender tu página y
a los lectores de pantalla (Accesibilidad) a narrarla a personas con discapacidad visual.
● <header>: Cabecera (logo, menú).
● <main>: El contenido principal único de esa página.
● <nav>: Bloques de navegación.
● <article> y <section>: Para dividir contenido.
● <footer>: Pie de página.
Formularios y Accesibilidad
Los formularios son la vía principal para que el usuario envíe datos.
● Usa siempre la etiqueta <label> vinculada a su <input> mediante el atributo for.
Esto permite hacer clic en el texto para activar el campo.
● Atributos importantes: type="email", required, placeholder.
html
<form>
<label for="correo">Tu Correo:</label>
<input type="email" id="correo" name="email" required>
<button type="submit">Enviar</button>
</form>
2.2 CSS: selectores, box model, flexbox y grid; responsive design
CSS (Cascading Style Sheets) define cómo se ven las cosas.
El Box Model (Modelo de Caja)
Todo en la web es una caja rectangular, aunque parezca un círculo. Entender esto es vital:
1. Content: El texto o imagen real.
2. Padding: Espacio interno (entre el contenido y el borde).
3. Border: El borde de la caja.
4. Margin: Espacio externo (separa la caja de otras cajas).
Layout Moderno: Flexbox y Grid
Olvida los "floats" del pasado.
● Flexbox: Ideal para diseños en una sola dimensión (una fila de botones o una
columna de tarjetas). Centrar algo es tan fácil como:
css
.padre { display: flex; justify-content: center; align-items: center; }
● Grid: Ideal para diseños bidimensionales complejos (maquetar toda la estructura de
la página con filas y columnas).
Responsive Design
Tu sitio debe verse bien en un celular y en una pantalla gigante. Usamos Media Queries:
css
/* Estilos para móviles primero (Mobile First) */
body { font-size: 16px; }
/* Cambios para pantallas grandes */
@media (min-width: 768px) {
body { font-size: 18px; }
2.3 JavaScript en el navegador: variables, funciones, arrays, DOM y
eventos
JavaScript (JS) da vida a la página.
Conceptos Básicos
● Variables: Usa const para valores que no cambian y let para los que sí. Evita var.
● Funciones: La sintaxis moderna (Arrow Functions) es más limpia:
● javascript
● const saludar = (nombre) => `Hola ${nombre}`;
El DOM y Eventos
JS interactúa con el HTML a través del DOM.
1. Seleccionar: [Link]('#miBoton')
2. Escuchar: Agregamos un "Event Listener" para reaccionar a acciones.
3. Manipular: Cambiamos clases, texto o estilos.
javascript
const boton = [Link]('#btn-alerta');
[Link]('click', () => {
alert('¡Hiciste clic!');
});
2.4 Mini-proyecto: Landing page responsive con interacción
Vamos a unir todo. Crearemos una sección de "Héroe" (presentación) que cambia de color y
tiene un menú móvil.
Estructura de archivos: [Link], [Link], [Link].
HTML (Resumido):
<nav>
<div class="logo">MiMarca</div>
<ul class="menu" id="menuLista">
<li><a href="#">Inicio</a></li>
<li><a href="#">Servicios</a></li>
</ul>
<button id="menuToggle">☰</button>
</nav>
<section class="hero">
<h1>Bienvenido a mi Web</h1>
<button id="cambiarColor">Cambiar Tema</button>
</section>
CSS (Clave para responsive):
/* Ocultar menú en móviles por defecto */
.menu { display: none; }
/* Clase para mostrar menú con JS */
.[Link] { display: block; flex-direction: column; }
/* En escritorio, siempre visible */
@media (min-width: 768px) {
.menu { display: flex; gap: 20px; }
#menuToggle { display: none; } /* Ocultar botón hamburguesa */
.tema-oscuro { background: #333; color: white; }
JavaScript:
const toggle = [Link]('#menuToggle');
const menu = [Link]('#menuLista');
const btnColor = [Link]('#cambiarColor');
const body = [Link];
// Menú hamburguesa
[Link]('click', () => {
[Link]('activo');
});
// Cambiar tema
[Link]('click', () => {
[Link]('tema-oscuro');
});
2.5 Ejercicios
1. Semántica: Toma un sitio web antiguo que use solo <div> e intenta reescribir su
estructura usando <header>, <main>, <section> y <footer>.
2. CSS Art: Dibuja un círculo rojo perfecto centrado en el medio de la pantalla usando
border-radius y Flexbox.
3. Lógica JS: Crea un input donde ingreses tu año de nacimiento y un botón que, al
pulsarlo, calcule tu edad y la muestre en un párrafo debajo.
Front-end Moderno
Hasta ahora, manipulábamos la web "a mano" con JavaScript estándar. Eso funciona bien
para sitios pequeños, pero cuando construimos aplicaciones complejas (como Facebook o
Airbnb), el código se vuelve un espagueti inmanejable. Aquí entran las librerías modernas
para poner orden.
3.1 Qué es un framework/biblioteca de UI
Imagina que estás construyendo un auto.
● Vanilla JS (JS puro): Es como fabricar cada tornillo, rueda y chasis desde cero.
Tienes control total, pero tardas años.
● Framework/Librería: Es tener las piezas prefabricadas (motor, puertas, asientos).
Solo tienes que ensamblarlas para que el auto funcione.
React (creada por Facebook) es técnicamente una librería porque se encarga solo de la
interfaz (la vista), dándote libertad para elegir cómo manejar rutas o datos. Nos permite
construir interfaces dividiéndolas en piezas pequeñas y reutilizables.
3.2 React: componentes, props, estado y JSX
Componentes
Son los bloques de construcción. Un botón es un componente, una barra de navegación es
otro. En React moderno, son simplemente Funciones de JavaScript que devuelven HTML (o
algo que se le parece).
JSX (JavaScript XML)
Es esa sintaxis extraña que parece HTML dentro de JS.
javascript
function Saludo() {
return <h1>Hola, soy un componente</h1>;
}
Nota: JSX requiere que todo esté envuelto en una sola etiqueta padre (o un fragmento
<>...</>).
Props (Propiedades)
Es cómo pasamos información de un componente Padre a un Hijo. Son de solo lectura.
javascript
function Usuario(props) {
return <p>Nombre: {[Link]}</p>;
// Uso: <Usuario nombre="Roxana" />
3.3 Vite: crear y ejecutar proyectos modernos
Antes se usaba "Create React App", pero es lento. Hoy el estándar de industria es Vite. Es
extremadamente rápido.
Pasos en terminal:
1. npm create vite@latest mi-proyecto-react -- --template react
2. cd mi-proyecto-react
3. npm install (instala las dependencias)
4. npm run dev (inicia el servidor de desarrollo)
¡Listo! Tienes un entorno profesional corriendo en segundos.
3.4 Hooks esenciales: useState y useEffect
Los Hooks son funciones especiales que permiten a los componentes funcionales "tener
memoria" y "ciclo de vida".
useState (Estado)
El estado son los datos que cambian en el tiempo. Si el estado cambia, React actualiza la
pantalla automáticamente (re-render).
javascript
import { useState } from 'react';
function Contador() {
const [cuenta, setCuenta] = useState(0); // [valor, funcionParaCambiarlo]
return <button onClick={() => setCuenta(cuenta + 1)}>Clicks: {cuenta}</button>;
useEffect (Efectos Secundarios)
Sirve para ejecutar código cuando algo sucede (al cargar el componente o cuando cambia
una variable). Ideal para llamadas a APIs.
javascript
import { useEffect } from 'react';
useEffect(() => {
[Link]("El componente se montó o actualizó");
}, []); // El array vacío [] significa "ejecutar solo una vez al inicio"
3.5 Listas, keys y formularios controlados
Listas
Usamos .map() para transformar arrays de datos en arrays de componentes. Siempre
necesitas una key única para que React identifique qué elemento cambió.
javascript
const frutas = ['Manzana', 'Pera', 'Uva'];
return (
<ul>
{[Link]((fruta, index) => <li key={index}>{fruta}</li>)}
</ul>
);
Formularios Controlados
En HTML, el input guarda su propio valor. En React, queremos que el estado controle el
input.
javascript
const [texto, setTexto] = useState("");
<input value={texto} onChange={(e) => setTexto([Link])} />
3.6 Enrutamiento con React Router
Las aplicaciones modernas son SPA (Single Page Applications). No recargan la página al
cambiar de ruta, solo cambian el contenido. Para esto usamos react-router-dom.
1. Instalar: npm install react-router-dom
2. Configurar en [Link] envolviendo la app en <BrowserRouter>.
3. Usar:
javascript
import { Routes, Route, Link } from 'react-router-dom';
function App() {
return (
<>
<nav><Link to="/">Home</Link> | <Link to="/perfil">Perfil</Link></nav>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/perfil" element={<Perfil />} />
</Routes>
</>
);
Importante: Usamos <Link> en lugar de <a> para evitar la recarga de página.
3.7 Build para producción
Cuando terminas, no subes tus archivos .jsx. Necesitas "compilar" todo a archivos
estáticos optimizados que el navegador entienda.
Ejecuta: npm run build.
Esto creará una carpeta dist/ con archivos HTML, CSS y JS minificados (comprimidos),
listos para subir a cualquier servidor.
3.8 Mini-proyecto: TODO SPA con persistencia local
Crearemos una lista de tareas que no se borra al refrescar.
Lógica principal:
1. Estado tareas (array de objetos {id, texto, completada}).
2. Input controlado para nueva tarea.
3. useEffect para leer localStorage al iniciar.
4. useEffect secundario para guardar en localStorage cada vez que tareas
cambie.
javascript
// Fragmento clave
useEffect(() => {
[Link]('mis-tareas', [Link](tareas));
}, [tareas]);
3.9 Ejercicios
1. Componente Tarjeta: Crea un componente Card que acepte titulo, imagen y
descripcion como props y los muestre con estilos bonitos.
2. Consumo de API: Usa useEffect y fetch para traer datos de "Rick and Morty API"
o "PokeAPI" y mostrarlos en una lista.
3. Rutas: Crea una app con 3 páginas: Inicio, Acerca de y Contacto. La página actual
debe tener un estilo diferente en el menú de navegación.
Gestión del Estado
En aplicaciones pequeñas, el estado local (useState) es suficiente. Pero cuando tu
aplicación crece, pasar datos de un componente abuelo a un bisnieto se vuelve una
pesadilla. En este capítulo aprenderemos a manejar los datos de forma profesional y
escalable.
4.1 Prop drilling y estado compartido
Imagina una fila de 10 personas pasando cubetas de agua para apagar un incendio. La
persona 1 llena la cubeta y se la pasa a la 2, la 2 a la 3, y así hasta la 10, que es quien
realmente la necesita. Las personas 2 a la 9 no necesitan el agua, solo son transportadoras.
En React, esto se llama Prop Drilling (Taladrado de props).
Ocurre cuando pasas una prop a través de componentes intermedios que no la usan, solo
para que llegue a un componente hijo muy profundo. Esto ensucia el código y hace que el
mantenimiento sea difícil.
4.2 Lifting state up: cuándo sirve y cuándo no
Antes de usar herramientas complejas, React nos sugiere "Elevar el estado" (Lifting State
Up).
Si dos componentes hermanos (por ejemplo, una lista de productos y un contador en el
carrito) necesitan los mismos datos, no puedes pasar datos entre hermanos.
● Solución: Mueves el estado (useState) a su padre común más cercano (ancestro
común).
● Cuándo sirve: Cuando la distancia entre el padre y los hijos es corta (1 o 2 niveles).
● Cuándo NO sirve: Cuando tienes que elevar el estado hasta la raíz de la aplicación
para que dos componentes lejanos se comuniquen. Ahí entra el Estado Global.
4.3 Context API: estado global simple (tema, usuario)
Context API viene integrado en React y nos permite "teletransportar" datos. Es ideal para
datos que son globales pero no cambian con demasiada frecuencia, como el usuario
autenticado o el tema (oscuro/claro).
Pasos:
1. Crear el contexto:
2. javascript
import { createContext } from 'react';
3. export const TemaContext = createContext(null);
4. Proveer el contexto (Provider): Envuelves tu app con él.
5. javascript
<[Link] value="oscuro">
<App />
6. </[Link]>
7. Consumir el contexto (useContext):
8. javascript
import { useContext } from 'react';
9. const tema = useContext(TemaContext); // Devuelve "oscuro"
4.4 Redux Toolkit: store, slices, acciones y async thunks
Para aplicaciones grandes con actualizaciones de estado frecuentes y complejas, Redux es
el rey. Usaremos Redux Toolkit (RTK), la versión moderna y simplificada.
● Store: Es el cerebro único. Una "caja fuerte" donde vive todo el estado de tu
aplicación.
● Slices: Son "rebanadas" del cerebro. Un slice para usuarios, otro para productos, otro
para notificaciones. Contienen el estado inicial y los "reducers" (funciones que dicen
cómo cambiar ese estado).
● Acciones: Son eventos. "Hice clic en agregar", "Se cargaron los datos".
● Dispatch: Es la forma de enviar una acción al Store.
Ejemplo de un Slice (Contador):
javascript
import { createSlice } from '@reduxjs/toolkit';
export const contadorSlice = createSlice({
name: 'contador',
initialState: { valor: 0 },
reducers: {
incrementar: (state) => { [Link] += 1 }, // RTK permite "mutar" el estado
visualmente
decrementar: (state) => { [Link] -= 1 },
},
});
export const { incrementar, decrementar } = [Link];
export default [Link];
4.5 Patrón de carga: loading, error, datos
Cuando trabajamos con datos asíncronos (APIs) en el estado global, siempre debemos
manejar tres estados visuales para una buena UX. Esto se suele manejar con Async Thunks
en Redux.
1. Loading (Cargando): El usuario hizo la petición, mostramos un spinner. isLoading
= true.
2. Success (Datos): La petición volvió con éxito. Guardamos los datos y isLoading =
false.
3. Error (Fallo): Algo salió mal. Guardamos el mensaje de error y isLoading =
false.
javascript
// En tu componente visual
if (isLoading) return <Spinner />;
if (error) return <p>Error: {error}</p>;
return <ListaDeDatos datos={data} />;
4.6 Mini-proyecto: TODO con estado global y notificaciones
Vamos a refactorizar la lista de tareas usando Redux Toolkit.
1. Instala: npm install @reduxjs/toolkit react-redux.
2. Configura el [Link].
3. Crea [Link].
● Estado inicial: { list: [], loading: false }.
● Reducers: addTodo, removeTodo, toggleTodo.
4. En tu componente principal, usa useSelector para leer las tareas y useDispatch
para lanzar las acciones.
5. javascript
const dispatch = useDispatch();
const tareas = useSelector((state) => [Link]);
6. const agregar = () => dispatch(addTodo({ id: 1, text: "Aprender Redux" }));
7. Extra: Añade un slice de "Notificaciones". Cuando agregues una tarea, haz un
dispatch también a notificacionesSlice para mostrar un mensaje "Tarea
agregada" en la esquina de la pantalla.
4.7 Ejercicios
1. Refactorización: Toma el ejercicio del "Carrito de Compras" (si lo hiciste
mentalmente) o crea uno simple. Pasa de usar useState y props a usar Context
API.
2. Redux Fetch: Crea una pequeña app que consuma la API de jsonplaceholder
(usuarios). Usa createAsyncThunk para manejar la petición y guarda los usuarios
en el Store de Redux. Muestra "Cargando..." mientras llegan los datos.
3. Depuración: Instala la extensión "Redux DevTools" en tu navegador y observa cómo
cambian las acciones y el estado en tiempo real mientras usas tu mini-proyecto.
Desarrollo Back-end con [Link] y Express
[Link] nos permite usar JavaScript (el mismo lenguaje que ya dominas) en el servidor. Esto
es revolucionario porque unifica el lenguaje en todo el stack. Express es el framework más
popular para [Link], minimalista y flexible, ideal para construir APIs.
5.1 Conceptos clave: rutas, controladores, middlewares, CORS
Rutas (Routes):
Son los caminos de tu aplicación. Definen qué URL (endpoint) y qué método HTTP (GET,
POST, etc.) responderán.
Ejemplo: GET /usuarios devuelve la lista de usuarios.
Controladores (Controllers):
Es la lógica de negocio. Es la función que se ejecuta cuando alguien llega a una ruta.
Ejemplo: La función que va a la base de datos, busca los usuarios y los devuelve.
Middlewares:
Son los porteros de tu discoteca. Son funciones que se ejecutan antes de llegar al
controlador final. Pueden modificar la petición, revisarla o detenerla.
● Uso común: Verificar si el usuario está logueado antes de dejarle ver datos privados.
CORS (Cross-Origin Resource Sharing):
Por seguridad, los navegadores bloquean peticiones entre dominios diferentes (ej: tu Front
en localhost:5173 pidiendo datos a tu Back en localhost:3000). Debemos configurar
CORS en el servidor para "dar permiso" a nuestro Front-end.
5.2 Estructura de proyecto y entorno (dotenv, scripts)
Un buen backend debe ser ordenado. No escribas todo en un solo archivo.
Estructura recomendada:
text
/src
/controllers (Lógica)
/routes (Rutas)
/models (Base de datos)
/middlewares (Validaciones)
[Link] (Configuración de Express)
[Link] (Punto de entrada)
Variables de Entorno (.env):
Nunca escribas contraseñas o claves secretas en tu código. Usa un archivo .env que no se
sube a GitHub (gracias al .gitignore).
env
PORT=3000
DB_PASSWORD=mi_secreto_super_seguro
Usamos la librería dotenv para leer estas variables.
Scripts en [Link]:
Usa nodemon para desarrollo (reinicia el servidor automáticamente al guardar cambios).
"dev": "nodemon src/[Link]"
5.3 Endpoints REST: CRUD de recursos
REST (Representational State Transfer) es un estilo de arquitectura. Se basa en recursos
(sustantivos) y métodos HTTP (verbos).
Vamos a crear un CRUD (Create, Read, Update, Delete) para "Tareas":
● GET /tareas: Obtener todas (Read).
● POST /tareas: Crear una nueva (Create).
● Los datos vienen en el body de la petición.
● GET /tareas/:id: Obtener una específica.
● PUT /tareas/:id: Actualizar una completa (Update).
● DELETE /tareas/:id: Borrar una (Delete).
Ejemplo simple en Express:
javascript
[Link]('/tareas', (req, res) => {
[Link]([{ id: 1, texto: "Aprender Node" }]);
});
5.4 Validación y manejo de errores
Nunca confíes en lo que envía el cliente. Siempre valida.
Si esperas un email, verifica que sea un email. Si falta un campo obligatorio, devuelve un
error 400 (Bad Request).
Librerías como express-validator o zod son útiles aquí.
Manejo de Errores (Try-Catch):
Envuelve tu código asíncrono en bloques try-catch. Si algo falla (ej. base de datos caída),
captura el error y envía una respuesta controlada (500 Internal Server Error) en lugar de dejar
que el servidor se cuelgue.
5.5 Logs y buenas prácticas de API
Logs:
[Link] está bien para empezar, pero en producción usamos librerías como morgan
o winston. Queremos saber: ¿Quién hizo la petición? ¿A qué hora? ¿Qué error ocurrió?
Buenas Prácticas:
1. Códigos de Estado HTTP: Úsalos correctamente.
● 200: OK.
● 201: Creado.
● 400: Error del cliente (datos mal).
● 401: No autorizado (sin login).
● 404: No encontrado.
● 500: Error del servidor.
2. JSON: Siempre responde con JSON.
3. Consistencia: Si devuelves { data: [...] } en una ruta, no devuelvas solo
[...] en otra.
5.6 Mini-proyecto: API de tareas
Crearemos nuestra primera API real.
1. npm init -y
2. npm install express cors dotenv (y npm install -D nodemon).
3. Crea [Link].
4. Define un array en memoria: let tareas = [].
5. Implementa las rutas:
● GET devuelve el array.
● POST hace [Link]([Link]) y devuelve la tarea nueva.
● DELETE filtra el array para quitar el ID recibido.
6. Prueba tu API usando Postman o Insomnia (herramientas para probar endpoints sin
necesidad de un frontend).
5.7 Ejercicios
1. Middleware de Logger: Escribe una función middleware manual que imprima en
consola "METODO url - fecha" cada vez que llegue una petición (ej: GET
/api/users - 12:00pm) y úsala en tu app.
2. Búsqueda: Añade un "query parameter" a tu GET /tareas para filtrar. Ej:
/tareas?completada=true debería devolver solo las hechas.
3. Error 404: Crea un middleware al final de tus rutas que capture cualquier petición
que no haya coincidido con ninguna ruta anterior y devuelva un JSON: {
"mensaje": "Ruta no encontrada" }.
4.
Bases de Datos y ORM
Hasta ahora, guardábamos los datos en arrays dentro de JavaScript. Eso es memoria volátil
(RAM). Ahora guardaremos los datos en el disco duro (o en la nube) para que persistan por
siempre. Además, aprenderemos a usar herramientas que nos permitan hablar con la base
de datos usando JavaScript, sin tener que aprender lenguajes de consulta complejos desde
cero.
6.1 SQL vs NoSQL: cuándo elegir cada una
Esta es la gran pregunta de entrevista y diseño de arquitectura.
SQL (Relacional - Ej: PostgreSQL, MySQL)
● Estructura: Tablas con filas y columnas (como Excel).
● Esquema: Rígido. Debes definir qué campos existen antes de guardar datos. Si
quieres agregar un campo nuevo, debes modificar la tabla.
● Relaciones: Muy fuerte para relacionar datos (Ej: Un Usuario tiene muchos Pedidos).
● Uso ideal: Sistemas financieros, inventarios estrictos, aplicaciones con muchas
relaciones complejas.
NoSQL (No Relacional - Ej: MongoDB)
● Estructura: Colecciones de Documentos (parecido a archivos JSON).
● Esquema: Flexible. Un documento puede tener campo "nombre" y otro no.
● Relaciones: Más débiles (aunque posibles). Se prefiere "anidar" datos.
● Uso ideal: Redes sociales, catálogos de productos variados, Big Data, prototipado
rápido.
6.2 PostgreSQL (SQL): esquemas, tablas, índices; Sequelize
Para trabajar con SQL en [Link], usaremos un ORM (Object-Relational Mapper) llamado
Sequelize.
El ORM traduce nuestro código JavaScript a sentencias SQL.
● Modelos: Definimos una clase en JS que representa una tabla.
javascript
const User = [Link]('User', {
firstName: [Link],
age: [Link]
});
● Tablas: Sequelize crea la tabla en la base de datos basándose en el modelo
(sincronización).
● Índices: Son como el índice de un libro. Permiten encontrar datos rápidamente sin
leer toda la tabla. Vitales para el rendimiento.
6.3 MongoDB (NoSQL): colecciones, documentos; Mongoose
Para MongoDB, la herramienta estándar en [Link] es Mongoose (un ODM - Object Data
Modeling). Aunque Mongo es "sin esquema", Mongoose nos ayuda a imponer cierto orden
desde el código para no volvernos locos.
● Colección: Equivalente a una tabla.
● Documento: Equivalente a una fila. Es un objeto JSON almacenado.
javascript
"_id": "507f1f77bcf86cd799439011",
"nombre": "Roxana",
"hobbies": ["Leer", "Codificar"] // ¡Podemos guardar arrays directamente!
}
6.4 Conexión, modelos y consultas
Veamos cómo se ve esto en código real usando Mongoose (es muy amigable para
empezar).
1. Conexión:
javascript
import mongoose from 'mongoose';
[Link]([Link].MONGO_URI)
.then(() => [Link]('DB Conectada'))
.catch(err => [Link](err));
2. Definir Modelo:
javascript
const TareaSchema = new [Link]({
texto: { type: String, required: true },
completada: { type: Boolean, default: false }
});
const Tarea = [Link]('Tarea', TareaSchema);
3. Consultas (Queries):
● Guardar: await [Link]({ texto: "Estudiar" });
● Buscar todas: const lista = await [Link]();
● Buscar una: const una = await [Link](id);
6.5 Patrones: paginación, filtros, proyecciones
Cuando tienes 1 millón de usuarios, no puedes hacer un [Link](). El servidor
explotaría intentando enviar todo eso.
● Paginación: Traer los datos por partes.
● Limit: "Dame solo 10".
● Skip (Offset): "Sáltate los primeros 20".
● Filtros: "Dame solo los usuarios activos".
javascript
// Ejemplo Mongoose
[Link]({ activo: true }).limit(10).skip(0);
● Proyecciones: "Dame el usuario, pero NO me mandes su contraseña".
Seleccionamos solo los campos necesarios para ahorrar ancho de banda.
6.6 Mini-proyecto: persistencia real para la API
Vamos a actualizar la API de Tareas del Capítulo 5 para usar MongoDB.
1. Crea una cuenta gratuita en MongoDB Atlas (base de datos en la nube). Obtén tu
"Connection String".
2. Instala Mongoose: npm install mongoose.
3. Conecta tu [Link] a la base de datos.
4. Crea una carpeta /models y el archivo [Link].
5. Refactoriza los controladores:
● Cambia [Link]() por await [Link]().
● Cambia [Link](tareas) por const tareas = await
[Link](); [Link](tareas).
● Recuerda usar async/await en tus rutas porque la base de datos tarda
unos milisegundos en responder.
6.7 Ejercicios
1. Diseño de Datos: Dibuja en un papel cómo sería la base de datos para una tienda
online. ¿Qué colecciones necesitas? (Productos, Usuarios, Compras). ¿Cómo se
relacionan?
2. Consultas Avanzadas: Usando tu nueva API con Mongo, crea un endpoint especial
que devuelva solo las tareas que ya están completadas.
3. Seguridad de datos: Implementa una validación en el modelo para que no se puedan
guardar tareas con texto vacío (Mongoose validation).
Autenticación y Seguridad
La seguridad es el pilar de la confianza en cualquier aplicación. Si tu sistema no es seguro,
los datos de tus usuarios corren peligro. En este capítulo, aprenderemos a verificar la
identidad de los usuarios (Autenticación) y a controlar qué pueden hacer dentro del sistema
(Autorización).
7.1 HTTP/HTTPS, cabeceras y políticas
La web se basa en el intercambio de mensajes, y debemos asegurar que esos mensajes no
sean interceptados.
● HTTP vs. HTTPS:
● HTTP: Envía la información en texto plano. Si un usuario envía su contraseña
"12345", cualquier persona conectada a la misma red Wi-Fi podría interceptar
el paquete y leerla.
● HTTPS: Utiliza protocolos SSL/TLS para encriptar la comunicación. Aunque
alguien intercepte el mensaje, solo verá caracteres sin sentido. En
producción, HTTPS es obligatorio.
● Cabeceras (Headers):
Son metadatos que viajan en cada petición. Para la seguridad, la cabecera más
importante es Authorization. Aquí es donde el cliente (navegador/app) envía su
"credencial" en cada petición para demostrar quién es.
● Formato estándar: Authorization: Bearer <token_secreto>
7.2 Autenticación con JWT: registro, login, refresh tokens
Las sesiones antiguas guardaban datos en la memoria del servidor. Hoy, en el mundo de las
APIs REST escalables, usamos Stateless Authentication (Autenticación sin estado)
mediante JWT (JSON Web Tokens).
¿Cómo funciona el flujo?
1. Registro: El usuario envía email y contraseña. El servidor guarda la contraseña
(encriptada) en la BD.
2. Login: El usuario envía sus credenciales. El servidor verifica y, si son correctas,
genera un Token (JWT) firmado digitalmente.
3. Uso: El servidor envía el JWT al cliente. El cliente lo guarda (generalmente en
localStorage o Cookies).
4. Peticiones: Para acceder a una ruta privada, el cliente envía el JWT en la cabecera. El
servidor verifica la firma del token y permite el paso.
Refresh Tokens:
Por seguridad, los JWT de acceso (Access Tokens) deben expirar rápido (ej. 15 minutos).
Para no obligar al usuario a loguearse cada 15 minutos, usamos un Refresh Token (de larga
duración) que sirve únicamente para pedir un nuevo Access Token sin reingresar la
contraseña.
7.3 Autorización por roles y permisos
Saber quién eres (Autenticación) es diferente a saber qué puedes hacer (Autorización).
● Autenticación: "¿Eres Juan?" -> Sí.
● Autorización: "¿Juan puede borrar la base de datos?" -> No, solo el Admin puede.
En el código, esto se maneja con Middlewares.
javascript
const isAdmin = (req, res, next) => {
if ([Link] !== 'admin') {
return [Link](403).json({ mensaje: 'Acceso denegado: Se requiere ser Admin' });
next(); // Si es admin, dejamos pasar la petición
};
// Uso en ruta
[Link]('/usuarios/:id', authMiddleware, isAdmin, deleteUser);
7.4 Seguridad básica: hashing, rate limiting, CSRF/XSS, validación
de entradas
No basta con loguearse, hay que proteger la fortaleza.
1. Hashing de Contraseñas:
NUNCA guardes contraseñas en texto plano. Si te hackean la base de datos, tendrás
un desastre.
Usa librerías como bcrypt o argon2. Estas transforman "secreto123" en algo
como $2b$10$Xw.... Es un proceso irreversible.
2. Rate Limiting:
Evita que un bot intente adivinar contraseñas probando mil veces por segundo.
Limita las peticiones (ej. "máximo 5 intentos de login por minuto") usando
express-rate-limit.
3. XSS y CSRF:
● XSS (Cross-Site Scripting): Ocurre cuando un atacante inyecta scripts
maliciosos en tu web (ej. en un comentario). React protege bastante contra
esto por defecto.
● CSRF: Engañar al navegador para hacer acciones sin que el usuario quiera.
Se mitiga usando Tokens y configurando bien las Cookies (SameSite).
4. Validación de Entradas:
Jamás confíes en lo que viene del usuario. Usa librerías como Zod o Joi en el
backend para asegurarte de que los datos tienen el formato correcto antes de
procesarlos.
7.5 Mini-proyecto: proteger rutas y datos del usuario
Vamos a blindar nuestra API de Tareas.
Pasos:
1. Modelo de Usuario: Crea un modelo User con email y password.
2. Registro: Crea un endpoint POST /auth/register. Usa [Link]() antes
de guardar el usuario.
3. Login: Crea un endpoint POST /auth/login. Usa [Link]() para
verificar la contraseña. Si coincide, usa la librería jsonwebtoken para firmar y
devolver un token.
4. Middleware de Autenticación: Crea una función que lea el header Authorization,
verifique el token con [Link]() e inyecte el usuario en la petición ([Link]
= decodedToken).
5. Proteger Rutas: Añade el middleware a las rutas de tareas.
6. Propiedad de los datos: Modifica el modelo de Tarea para tener un campo userId.
Ahora, al crear una tarea, guarda el ID del usuario logueado. Al listar tareas, filtra:
[Link]({ userId: [Link] }).
Resultado: Juan solo puede ver y editar las tareas de Juan.
7.6 Ejercicios
1. Hash Manual: Crea un script pequeño con bcrypt. Define una contraseña, hasheala,
e imprime el resultado. Luego intenta usar la función compare con la contraseña
correcta e incorrecta para ver qué devuelve true o false.
2. Ruta "Solo VIP": Añade un campo booleano isVip a tu modelo de usuario. Crea una
ruta /ofertas-especiales que solo devuelva datos si el usuario logueado tiene
isVip: true.
3. Investigación: Busca en Google "OWASP Top 10". Es la lista de las vulnerabilidades
más críticas en la web. Lee sobre la número 1.
Construcción de APIs RESTful
Crear endpoints es fácil; diseñar una API que otros desarrolladores amen usar es un arte. En
este capítulo, nos enfocaremos en las convenciones internacionales que hacen que tu API
sea predecible, escalable y fácil de mantener.
8.1 Diseño de recursos y rutas; versionado
Recursos y Nombres (Sustantivos, no Verbos)
REST se basa en recursos. Las URLs deben describir qué estás buscando, no qué estás
haciendo.
● ❌ Mal: /obtenerUsuarios, /crearNuevaTarea, /borrar-todo
● ✅ Bien: /usuarios, /tareas
La acción se define con el método HTTP (GET, POST, DELETE), no con la URL.
Jerarquías y Anidamiento
Si un recurso depende de otro, la URL debe reflejarlo.
● Ejemplo: "Quiero los comentarios de la foto número 5".
● Ruta: GET /fotos/5/comentarios
Versionado
Las APIs cambian con el tiempo. Si cambias la estructura de los datos, podrías romper la
aplicación móvil que usa tu API. Para evitar esto, versionamos la API.
La forma más común es en la URL:
● [Link]
● Si haces cambios drásticos, lanzas /v2/tareas y mantienes la v1 funcionando un
tiempo.
8.2 Idempotencia, códigos de estado y convenciones
Idempotencia
Es un concepto matemático clave en redes. Una operación es idempotente si puedes
ejecutarla múltiples veces y el resultado en el servidor es el mismo que si la hubieras
ejecutado una sola vez.
● GET (Idempotente): Pedir la lista 10 veces no cambia nada.
● DELETE (Idempotente): Borrar el recurso ID 5. La primera vez lo borra (200 OK). La
segunda vez ya no existe (404 Not Found), pero el estado del servidor es el mismo
(el recurso no está).
● POST (NO Idempotente): Si envías la petición de "Crear Tarea" 10 veces, creas 10
tareas duplicadas.
Códigos de Estado (Status Codes)
Sé preciso. No devuelvas siempre 200.
● 200 OK: Todo bien.
● 201 Created: Éxito y se creó un recurso (ideal para POST).
● 204 No Content: Éxito, pero no hay nada que devolver (ideal para DELETE).
● 400 Bad Request: El cliente envió datos mal formados.
● 401 Unauthorized: No estás logueado.
● 403 Forbidden: Estás logueado, pero no tienes permiso.
● 404 Not Found: El recurso no existe.
● 500 Internal Server Error: Error de código en tu servidor.
8.3 Documentación de API (OpenAPI/Swagger)
Una API sin documentación es inservible para otros. El estándar mundial es OpenAPI
(anteriormente conocido como Swagger).
Esto nos permite generar una página web interactiva donde los desarrolladores pueden ver
tus endpoints, qué parámetros requieren y ¡probarlos directamente!
Herramientas en [Link]:
Usamos swagger-jsdoc (para escribir la doc en comentarios en el código) y
swagger-ui-express (para generar la web visual).
Ejemplo de comentario JSDoc para Swagger:
javascript
/**
* @swagger
* /tareas:
* get:
* description: Obtiene todas las tareas
* responses:
* 200:
* description: Éxito
*/
[Link]('/tareas', ...);
8.4 Testing de API e integración
Aunque veremos pruebas a fondo en el Capítulo 10, aquí hablamos de Integration Testing
para APIs.
Significa probar la API como una "caja negra": enviar una petición HTTP real y verificar la
respuesta.
Herramienta recomendada: Supertest.
javascript
const request = require('supertest');
const app = require('./app');
it('GET /tareas debe devolver JSON', async () => {
const response = await request(app).get('/api/v1/tareas');
expect([Link]).toBe(200);
expect([Link]['content-type']).toMatch(/json/);
});
8.5 Mini-proyecto: API documentada y testeada
Vamos a profesionalizar nuestra API de Tareas.
1. Refactorizar Rutas: Mueve todas tus rutas para que empiecen con /api/v1.
2. Instalar Swagger:
npm install swagger-jsdoc swagger-ui-express
3. Configurar Swagger:
Crea un archivo de configuración y define una ruta /api-docs.
4. Documentar: Añade los comentarios YAML sobre tus rutas de Tareas (GET y POST).
5. Resultado: Al entrar a [Link] verás una interfaz
azul bonita donde puedes probar tu API sin usar Postman.
8.6 Ejercicios
1. Versionado: Crea una ruta /api/v2/tareas que devuelva las tareas con una
estructura diferente (por ejemplo, envolviendo los datos en un objeto { data:
[...], timestamp: ... }). Comprueba que la v1 sigue funcionando igual.
2. Códigos de Estado: Revisa tu controlador de DELETE. Asegúrate de que si el ID no
existe, devuelva 404. Si se borra bien, intenta devolver 204 (sin cuerpo) y verifica qué
pasa en Postman.
3. Documentación: Documenta el endpoint de POST /auth/login en Swagger,
especificando claramente que requiere email y password en el body.
DevOps Básico
"En mi máquina funciona". Esta es la frase más famosa y temida en la programación.
DevOps (Development + Operations) es la cultura y conjunto de herramientas que busca
eliminar ese problema, automatizando la entrega de software para que sea rápida y segura.
9.1 Conceptos: entornos, variables, logs, monitoreo
Para trabajar profesionalmente, debemos separar los lugares donde vive el código:
Entornos:
1. Desarrollo (Development): Tu computadora (Localhost). Aquí rompes cosas y
experimentas.
2. Pruebas (Staging/QA): Un servidor idéntico al de producción. Aquí se prueba que
todo funcione integrado antes de lanzar.
3. Producción: El servidor real que usan los clientes. Aquí la estabilidad es sagrada.
Variables de Entorno:
La configuración cambia según el entorno.
● En Local, tu base de datos es localhost:27017.
● En Producción, es mongodb+srv://atlas-cluster....
Nunca "quemes" (hardcode) estas credenciales en el código. Úsalas siempre a
través de [Link].
Logs y Monitoreo:
En producción, no tienes una terminal abierta viendo [Link]. Necesitas sistemas
que guarden esos registros (logs) en archivos o servicios en la nube (como Datadog o
Sentry) para saber si algo falló a las 3:00 AM.
9.2 Docker: contenedores para app y base de datos
Docker revolucionó la industria. Permite empaquetar tu aplicación, tus librerías y hasta tu
versión de [Link] en una "caja" llamada Contenedor.
● Imagen: Es la "receta" o el molde (clase).
● Contenedor: Es la instancia en ejecución (objeto).
Dockerfile:
Es el archivo donde defines la receta.
dockerfile
# Usar una base oficial de Node
FROM node:18-alpine
# Crear directorio de trabajo
WORKDIR /app
# Copiar dependencias e instalarlas
COPY package*.json ./
RUN npm install
# Copiar el resto del código
COPY . .
# Exponer el puerto
EXPOSE 3000
# Comando para iniciar
CMD ["npm", "start"]
Si ejecutas este contenedor en Windows, Linux o Mac, funcionará exactamente igual. Adiós
al "en mi máquina funciona".
9.3 Despliegue: opciones (VPS, PaaS, serverless)
¿Dónde ponemos nuestro código para que el mundo lo vea?
1. PaaS (Platform as a Service): Recomendado para empezar.
Proveedores como Render, Railway, Vercel o Heroku. Tú les das tu código (o
conectas tu GitHub) y ellos se encargan de los servidores, redes y escalado. Es fácil
pero puede ser más caro a gran escala.
● Front-end: Vercel, Netlify.
● Back-end: Render, Railway.
2. VPS (Virtual Private Server):
Alquilas una computadora vacía en la nube (DigitalOcean, AWS EC2). Tienes control
total, pero debes configurar Linux, seguridad y actualizaciones manualmente.
3. Serverless:
AWS Lambda o Google Cloud Functions. No pagas por un servidor encendido las
24hs, solo pagas por los milisegundos que tarda tu función en ejecutarse.
9.4 CI/CD: integración y despliegue continuo
Imagina que cada vez que guardas cambios en GitHub, un robot automáticamente:
1. Descarga tu código.
2. Instala las dependencias.
3. Ejecuta las pruebas (Testing).
4. Si las pruebas pasan, sube el código a Producción.
Esto es CI/CD (Continuous Integration / Continuous Deployment).
La herramienta más popular y gratuita para proyectos open source es GitHub Actions. Se
configura con un archivo .yaml en tu repositorio.
9.5 Mini-proyecto: app contenedorizada y desplegada
Vamos a poner tu API en internet.
1. Dockerizar:
● Crea un Dockerfile en la raíz de tu API.
● Crea un archivo .dockerignore (para no copiar node_modules ni .env).
● Prueba localmente: docker build -t mi-api . y docker run -p
3000:3000 mi-api.
2. Despliegue en Render (Gratis):
● Sube tu código a GitHub.
● Crea una cuenta en [Link].
● Selecciona "New Web Service" y conecta tu repo.
● Configura las Environment Variables en el panel de Render (pega tu
MONGO_URI de Atlas).
● ¡Desplegar! Render detectará que es una app Node, instalará y ejecutará.
● Obtendrás una URL pública:
[Link]
9.6 Ejercicios
1. Docker Compose: Investiga qué es [Link]. Intenta crear uno que
levante tu API y una base de datos MongoDB local al mismo tiempo con un solo
comando.
2. Romper Producción (Simulacro): Cambia una variable de entorno en Render para que
sea incorrecta. Observa qué pasa en los "Logs" del panel de control de Render. Esto
te enseña a depurar en la nube.
3. GitHub Actions: (Avanzado) Configura un workflow simple en GitHub que solo
imprima "El código se ha subido correctamente" cada vez que haces un push. Es el
primer paso para un CI/CD real.
Pruebas y Debugging
Imagina que eres un mecánico de Fórmula 1. Antes de la carrera, no solo esperas que el
auto arranque; pruebas cada tornillo, pruebas el motor en el banco de pruebas y finalmente
pruebas el auto en la pista. En el desarrollo de software, hacemos lo mismo para evitar que
el usuario final encuentre errores (bugs).
10.1 Pruebas unitarias, integración y end-to-end
No todas las pruebas son iguales. Se dividen en tres niveles principales:
1. Pruebas Unitarias (Unit Testing):
Pruebas la parte más pequeña de tu código de forma aislada (una función, un
componente simple).
● Ejemplo: Una función sumar(a, b) debe devolver 4 si le paso 2 y 2. No
importa si la base de datos funciona o no, solo me importa esa función.
2. Pruebas de Integración (Integration Testing):
Pruebas cómo interactúan dos o más piezas juntas.
● Ejemplo: Cuando hago clic en el botón "Guardar" (Front), ¿se envía la petición
correcta a la API (Back)? Aquí verificamos la comunicación.
3. Pruebas de Extremo a Extremo (E2E - End to End):
Simulan a un usuario real navegando por tu web. Un robot abre el navegador, hace
clic, escribe y verifica resultados.
● Ejemplo: El robot se registra, busca un producto, lo añade al carrito y paga.
10.2 Herramientas: Jest, Testing Library, Supertest, Playwright
El ecosistema de JavaScript es rico en herramientas de testing:
● Jest: Es el "Test Runner" más popular. Es quien ejecuta las pruebas y te dice si
pasaron (verde) o fallaron (rojo). Sirve para todo el stack.
● React Testing Library (RTL): Estándar para probar componentes React. Su filosofía
es: "Prueba tus componentes como los usaría el usuario". No busca si la variable
[Link] cambió, busca si en la pantalla aparece el texto "Hola Juan".
● Supertest: (Visto en el Cap 8) Ideal para probar endpoints de APIs ([Link]) sin
necesidad de abrir un navegador.
● Playwright (o Cypress): Herramientas modernas para E2E. Permiten automatizar
navegadores Chromium, Firefox y WebKit para ver tu app como la ven tus usuarios.
10.3 Estrategia de cobertura y pirámide de testing
La Pirámide de Testing
Es una guía sobre cuántas pruebas escribir de cada tipo:
● Base (Ancha): Pruebas Unitarias. Son rápidas de escribir y de ejecutar
(milisegundos). Debes tener muchas.
● Medio: Pruebas de Integración.
● Punta (Estrecha): Pruebas E2E. Son lentas y frágiles (si cambias un botón de lugar, la
prueba puede fallar). Debes tener pocas, solo para flujos críticos (ej: Login, Pago).
Cobertura (Code Coverage)
Es una métrica que te dice qué porcentaje de tu código fue ejecutado durante las pruebas.
● Si tienes una función con un if/else y tu prueba solo pasa por el if, tu cobertura
no es del 100%.
● Nota: No te obsesiones con el 100%. Llegar al 80% suele ser suficiente y saludable.
10.4 Debugging: lectura de stack traces, breakpoints
Cuando algo falla, no entres en pánico.
Stack Trace (Rastro de la pila)
Es ese texto rojo y feo que aparece en la consola. Es tu mejor amigo. Léelo de arriba a abajo.
1. ¿Qué pasó? El mensaje de error (ej: TypeError: Cannot read properties of
undefined).
2. ¿Dónde pasó? Busca el primer archivo que sea tuyo (no de node_modules). Te dirá
src/controllers/[Link]:10 (Línea 25, columna 10).
Breakpoints (Puntos de interrupción)
Deja de llenar tu código de [Link].
En VS Code (o Chrome DevTools), puedes hacer clic al lado del número de línea para poner
un punto rojo.
Cuando ejecutes el código en modo "Debug", la ejecución se congelará en ese punto. Podrás
pasar el mouse por encima de las variables para ver qué valor tienen en ese preciso
instante.
10.5 Mini-proyecto: suite de pruebas y reporte
Vamos a añadir pruebas a nuestro proyecto con Jest.
1. Configuración:
En tu proyecto de [Link] o React:
npm install --save-dev jest
2. Prueba Unitaria (Lógica pura):
Crea un archivo [Link] con una función sumar y un archivo [Link].
javascript
// [Link]
const { sumar } = require('./utils');
test('suma 1 + 2 y devuelve 3', () => {
expect(sumar(1, 2)).toBe(3);
});
3. Ejecutar:
En [Link], añade "test": "jest". Ejecuta npm test. ¡Verás tu primer check
verde!
4. Cobertura:
npm test -- --coverage
Esto generará una carpeta llamada coverage. Si abres el archivo
coverage/lcov-report/[Link] en tu navegador, verás una interfaz gráfica
increíble donde puedes navegar por tus archivos y ver exactamente qué líneas de código se
ejecutaron y cuáles no (resaltadas en rojo).
5. Prueba de Componente (React):
Si estás en el Front-end, prueba que tu componente de Tarea renderice el texto correcto.
javascript
// [Link]
import { render, screen } from '@testing-library/react';
import Tarea from './Tarea';
test('Renderiza el texto de la tarea', () => {
render(<Tarea texto="Comprar leche" />);
// Buscamos si el texto existe en el documento
const elemento = [Link](/Comprar leche/i);
expect(elemento).toBeInTheDocument();
});
El objetivo del mini-proyecto es tener al menos una prueba unitaria en el backend y una
prueba de componente en el frontend, y generar el reporte HTML de cobertura.
10.6 Ejercicios
1. Test Driven Development (TDD):
Esta metodología propone escribir la prueba antes que el código.
● Desafío: Escribe un test para una función llamada esEmailValido(email)
que debe devolver true o false. Ejecuta el test (fallará porque la función
no existe). Luego, crea la función y escribe el código justo y necesario para
que el test pase.
2. Snapshot Testing:
En React con Jest, investiga qué es un "Snapshot". Crea una prueba para un
componente estático (ej. el Header). La primera vez guardará una "foto" del HTML.
Cambia algo en el Header manualmente y corre el test de nuevo para ver cómo Jest
te avisa que la interfaz cambió inesperadamente.
3. Debugging Detective:
Pídele a ChatGPT (o a un amigo) que introduzca un error lógico sutil en una de tus
funciones (por ejemplo, cambiar un > por >=). Usa el debugger de VS Code con
Breakpoints para seguir la ejecución paso a paso y encontrar dónde está el fallo sin
usar [Link].
Aplicaciones en Tiempo Real
Hasta ahora, nuestra comunicación con el servidor ha sido unidireccional o bajo demanda
(el cliente pide, el servidor responde). Pero, ¿qué pasa cuando necesitamos que el servidor
"avise" al cliente de algo inmediatamente, como en un chat o una notificación? Aquí entran
los WebSockets.
11.1 WebSockets: Conceptos
El protocolo HTTP es "stateless" (sin estado) y basado en petición-respuesta. Para saber si
hay datos nuevos, tendríamos que refrescar la página o hacer polling (preguntar cada 5
segundos).
WebSockets resuelve esto creando un túnel de comunicación bidireccional y persistente
(full-duplex) entre el cliente y el servidor. Una vez establecida la conexión (handshake),
ambos pueden enviarse mensajes en cualquier momento con muy baja latencia.
11.2 [Link] o ws
Existen bibliotecas nativas como ws, pero en este libro utilizaremos [Link].
● ¿Por qué? [Link] maneja automáticamente las desconexiones, reconexiones y
ofrece compatibilidad con navegadores antiguos (usando long-polling si los
WebSockets fallan).
● Concepto clave: Se basa en eventos (emit para enviar, on para escuchar).
11.3 Sincronización y eventos
La lógica es simple:
1. Servidor: Escucha una conexión (connection).
2. Cliente: Emite un evento, ej: [Link]('mensaje', 'Hola mundo').
3. Servidor: Recibe el evento y lo retransmite a todos los demás conectados ([Link])
o solo a uno ([Link]).
Ejemplo de flujo: Un usuario da "Like" a una foto -> El servidor recibe el like -> El servidor
avisa a todos los clientes conectados -> Todos los navegadores actualizan el contador de
likes al instante sin recargar.
11.4 Mini-proyecto: Tablero en Vivo
Crearemos un Tablero de Estado del Equipo.
● Funcionalidad: Varios usuarios pueden conectarse. Cada usuario tiene un interruptor
para señalar su estado: "Disponible", "En reunión" o "Almorzando".
● Tech: [Link] (servidor socket), React (cliente).
● Reto: Cuando Pepito cambia su estado a "En reunión", la pantalla de Juanita debe
actualizarse sola instantáneamente.
11.5 Ejercicios
1. Chat Privado (Salas): Investiga el concepto de rooms en [Link]. Crea una
pequeña app donde puedas unirte a una sala llamada "General" o "Deportes" y que
los mensajes no se mezclen.
2. Indicador de "Escribiendo...": Usa el evento focus o keypress en el input del chat
para enviar un evento al servidor, y que este avise al otro usuario que estás
escribiendo.
3. Notificaciones Toast: Integra WebSockets con una librería de alertas (como
react-toastify). Dispara una notificación visual en el navegador cuando el
servidor emita un evento de "Nueva Tarea Asignada".
Proyecto Final
Este capítulo no enseña sintaxis nueva, sino Ingeniería de Software. Vamos a construir una
aplicación completa, simulando un entorno profesional real.
Sugerencia de proyecto: Un Clon simplificado de E-commerce o una Plataforma de Cursos.
12.1 Diseño funcional y técnico
Antes de escribir una línea de código:
● Wireframes: Dibuja las pantallas en papel o Figma (Login, Catálogo, Carrito,
Dashboard Admin).
● Modelo de Datos: Define tus tablas/colecciones. (Ej: Usuarios, Productos, Ordenes).
● Stack: MERN (MongoDB, Express, React, Node) o PERN (PostgreSQL).
12.2 Roadmap y organización
Divide y vencerás. Usa Trello o GitHub Projects.
1. Semana 1: Backend (Modelos, Auth, CRUD básico).
2. Semana 2: Frontend (Rutas, Componentes base, Conexión con API).
3. Semana 3: Features avanzadas (Pasarela de pago simulada, subida de imágenes).
12.3 Implementación incremental (MVP)
No busques la perfección, busca el Producto Mínimo Viable (MVP).
● Primero logra que un usuario pueda ver productos.
● Luego, que pueda registrarse.
● Finalmente, que pueda comprar.
● Si te sobra tiempo, añade modo oscuro o animaciones.
12.4 Pruebas, documentación y métricas
● Documentación: Escribe un [Link] impecable. Explica cómo instalar el
proyecto, las variables de entorno necesarias y qué hace la app.
● Pruebas: Añade tests de integración para el flujo de compra crítico.
12.5 Despliegue y checklist final
Lleva tu obra al mundo:
● Frontend en Vercel o Netlify.
● Backend en Render, Railway o Heroku.
● Base de datos en Mongo Atlas o Neon (Postgres).
● Checklist: ¿Quitaste los [Link]? ¿Las claves secretas están en .env y no en
el código? ¿Funciona en el móvil?
12.6 Presentación y reflexión
Cómo vender tu trabajo. Prepara un pequeño guion:
1. El problema que resuelves.
2. Las tecnologías usadas y por qué.
3. Demo en vivo (¡que funcione!).
4. Lecciones aprendidas y qué mejorarías en la versión 2.0.
Conclusiones y Recursos
13.1 Lecciones y siguientes pasos
El desarrollo Fullstack es un maratón, no un sprint. Has aprendido a conectar todas las
piezas del rompecabezas. Lo más importante que te llevas no es saber React o Node de
memoria, sino la capacidad de aprender a aprender y entender cómo fluyen los datos.
13.2 Rutas de especialización
Ahora que conoces el panorama general, puedes elegir profundizar:
● Frontend Specialist: Profundizar en animaciones, accesibilidad, [Link], WebGL.
● Backend Specialist: Microservicios, bases de datos avanzadas, Go, Rust, Java.
● DevOps/Cloud: AWS, Kubernetes, Terraform, escalabilidad masiva.
● Arquitecto de Software: Patrones de diseño, system design.
13.3 Recursos de la autora
Aquí incluyo enlaces a repositorios con el código final de los proyectos del libro, mi canal de
Discord para dudas y artículos recomendados para mantenerse al día.
Apéndices
A. Glosario
Un diccionario rápido de términos técnicos para consulta inmediata:
● Callback, Promise, Async/Await, Middleware, ORM, Transpilación, Hydration, etc.
B. Referencias y Bibliografía (Autoría de Roxana Rolón)
Lista de libros, documentación oficial (MDN, React Docs, Node Docs) y cursos que
inspiraron o complementan este material. Se da crédito a las fuentes originales y se
recomienda lectura adicional.
C. Plantillas, snippets y checklists
● .gitignore estándar: Qué ignorar en proyectos Node.
● Estructura de carpetas recomendada: Para proyectos pequeños y medianos.
● Cheat Sheet de comandos: Git, NPM y Docker básicos.
● Checklist de Code Review: Qué buscar antes de aprobar un Pull Request.
Índice
1. Introducción a la Programación Fullstack
1.1 Qué es Fullstack: front-end, back-end y visión integral
1.2 Cómo funciona la web: cliente, servidor, HTTP/HTTPS, JSON y DOM
1.3 Herramientas esenciales: navegador, VS Code, [Link], Git/GitHub
1.4 Hola Mundo en el navegador y en [Link]
1.5 Primer repositorio en GitHub
1.6 Ejercicios y mini-proyecto: página de perfil
2. Fundamentos de Desarrollo Web
2.1 HTML: estructura y semántica; formularios y accesibilidad
2.2 CSS: selectores, box model, flexbox y grid; responsive design
2.3 JavaScript en el navegador: variables, funciones, arrays, DOM y eventos
2.4 Mini-proyecto: landing page responsive
2.5 Ejercicios
3. Front-end Moderno
3.1 Qué es un framework/biblioteca de UI
3.2 React: componentes, props, estado y JSX
3.3 Vite: crear y ejecutar proyectos
3.4 Hooks: useState y useEffect
3.5 Listas, keys y formularios controlados
3.6 Enrutamiento con React Router
3.7 Build para producción
3.8 Mini-proyecto: TODO SPA con persistencia
3.9 Ejercicios
4. Gestión del Estado
4.1 Prop drilling y estado compartido
4.2 Lifting state up
4.3 Context API
4.4 Redux Toolkit: store, slices, thunks
4.5 Patrón de carga: loading, error, datos
4.6 Mini-proyecto: TODO con estado global
4.7 Ejercicios
5. Desarrollo Back-end con [Link] y Express
5.1 Rutas, controladores, middlewares, CORS
5.2 Estructura y entorno (dotenv, scripts)
5.3 Endpoints REST: CRUD
5.4 Validación y manejo de errores
5.5 Logs y buenas prácticas
5.6 Mini-proyecto: API de tareas
5.7 Ejercicios
6. Bases de Datos y ORM
6.1 SQL vs NoSQL
6.2 PostgreSQL + Sequelize
6.3 MongoDB + Mongoose
6.4 Conexión, modelos y consultas
6.5 Paginación, filtros e índices
6.6 Mini-proyecto: persistencia real
6.7 Ejercicios
7. Autenticación y Seguridad
7.1 HTTP/HTTPS y cabeceras
7.2 JWT: registro, login, refresh
7.3 Roles y permisos
7.4 Seguridad básica: hashing, rate limiting, CSRF/XSS
7.5 Mini-proyecto: rutas protegidas
7.6 Ejercicios
8. Construcción de APIs RESTful
8.1 Diseño de recursos y versionado
8.2 Idempotencia y códigos de estado
8.3 Documentación (OpenAPI/Swagger)
8.4 Testing de API e integración
8.5 Mini-proyecto: API documentada y testeada
8.6 Ejercicios
9. DevOps Básico
9.1 Entornos, variables, logs, monitoreo
9.2 Docker: contenedores
9.3 Despliegue (VPS, PaaS, serverless)
9.4 CI/CD
9.5 Mini-proyecto: app contenedorizada y desplegadas
9.6 Ejercicios
10. Pruebas y Debugging
10.1 Unitarias, integración y E2E
10.2 Herramientas: Jest, Testing Library, Supertest, Playwright
10.3 Estrategia y cobertura
10.4 Debugging: stack traces y breakpoints
10.5 Mini-proyecto: suite de pruebas
10.6 Ejercicios
11. Aplicaciones en Tiempo Real
11.1 WebSockets: conceptos
11.2 [Link] o ws
11.3 Sincronización y eventos
11.4 Mini-proyecto: tablero en vivo
11.5 Ejercicios
12. Proyecto Final
12.1 Diseño funcional y técnico
12.2 Roadmap y organización
12.3 Implementación incremental
12.4 Pruebas, documentación y métricas
12.5 Despliegue y checklist final
12.6 Presentación y reflexión
13. Conclusiones y Recursos
13.1 Lecciones y siguientes pasos
13.2 Rutas de especialización
13.3 Recursos de la autora
Apéndices
A. Glosario
B. Referencias y Bibliografía (Autoría de Roxana Rolón)
C. Plantillas, snippets y checklists