# Construye una App Bancaria Parte 3: Métodos para Obtener y Usar Datos Piensa en la computadora de la Enterprise en Star Trek: cuando el Capitán Picard pregunta por el estado de la nave, la información aparece al instante sin que toda la interfaz se apague y se reconstruya. Ese flujo constante de información es precisamente lo que estamos construyendo aquí con la obtención dinámica de datos. Ahora mismo, tu app bancaria es como un periódico impreso: informativa pero estática. Vamos a transformarla en algo más parecido al centro de control de la NASA, donde los datos fluyen continuamente y se actualizan en tiempo real sin interrumpir el flujo del usuario. Aprenderás a comunicarte con servidores de manera asíncrona, manejar datos que llegan en diferentes momentos y transformar la información en bruto en algo significativo para tus usuarios. Esta es la diferencia entre una demo y un software listo para producción. ## ⚡ Lo que Puedes Hacer en los Próximos 5 Minutos **Ruta rápida para desarrolladores ocupados** ```mermaid flowchart LR A[⚡ 5 minutos] --> B[Configurar servidor API] B --> C[Probar fetch con curl] C --> D[Crear función de inicio de sesión] D --> E[Ver datos en acción] ``` - **Minuto 1-2**: Inicia tu servidor API (`cd api && npm start`) y prueba la conexión - **Minuto 3**: Crea una función básica `getAccount()` usando fetch - **Minuto 4**: Conecta el formulario de inicio de sesión con `action="javascript:login()"` - **Minuto 5**: Prueba el inicio de sesión y observa cómo aparecen los datos de la cuenta en la consola **Comandos de prueba rápidos**: ```bash # Verificar que la API esté en funcionamiento curl http://localhost:5000/api # Probar la obtención de datos de la cuenta curl http://localhost:5000/api/accounts/test ``` **Por qué esto importa**: En 5 minutos, verás la magia de la obtención asíncrona de datos que potencia todas las aplicaciones web modernas. Esta es la base que hace que las apps se sientan rápidas y vivas. ## 🗺️ Tu Ruta de Aprendizaje a través de Aplicaciones Web Basadas en Datos ```mermaid journey title De Páginas Estáticas a Aplicaciones Dinámicas section Entendiendo la Evolución Recargas tradicionales de páginas: 3: You Descubrir beneficios de AJAX/SPA: 5: You Dominar patrones Fetch API: 7: You section Construyendo Autenticación Crear funciones de inicio de sesión: 4: You Manejar operaciones asíncronas: 6: You Administrar sesiones de usuario: 8: You section Actualizaciones Dinámicas de UI Aprender manipulación del DOM: 5: You Construir displays de transacciones: 7: You Crear dashboards responsivos: 9: You section Patrones Profesionales Renderizado basado en plantillas: 6: You Estrategias de manejo de errores: 7: You Optimización de rendimiento: 8: You ``` **Destino de tu ruta**: Al final de esta lección, entenderás cómo las aplicaciones web modernas obtienen, procesan y muestran datos dinámicamente, creando las experiencias de usuario fluidas que esperamos de aplicaciones profesionales. ## Quiz Pre-Clase [Quiz pre-clase](https://ff-quizzes.netlify.app/web/quiz/45) ### Prerrequisitos Antes de sumergirte en la obtención de datos, asegúrate de tener estos componentes listos: - **Lección previa**: Completa el [Formulario de Inicio de Sesión y Registro](../2-forms/README.md) — construiremos sobre esta base - **Servidor local**: Instala [Node.js](https://nodejs.org) y [ejecuta el servidor API](../api/README.md) para proveer datos de cuenta - **Conexión API**: Prueba la conexión a tu servidor con este comando: ```bash curl http://localhost:5000/api # Respuesta esperada: "API Bancaria v1.0.0" ``` Esta prueba rápida asegura que todos los componentes se comuniquen correctamente: - Verifica que Node.js esté funcionando adecuadamente en tu sistema - Confirma que tu servidor API está activo y responde - Valida que tu app puede alcanzar el servidor (como verificar contacto por radio antes de una misión) ## 🧠 Visión General del Ecosistema de Gestión de Datos ```mermaid mindmap root((Gestión de Datos)) Authentication Flow Login Process Validación de Formularios Verificación de Credenciales Gestión de Sesiones User State Objeto Global de Cuenta Guardias de Navegación Manejo de Errores API Communication Fetch Patterns Solicitudes GET Solicitudes POST Respuestas de Error Data Formats Procesamiento JSON Codificación URL Análisis de Respuestas Dynamic UI Updates DOM Manipulation Actualizaciones Seguras de Texto Creación de Elementos Clonación de Plantillas User Experience Actualizaciones en Tiempo Real Mensajes de Error Estados de Carga Security Considerations XSS Prevention Uso de textContent Saneamiento de Entradas Creación Segura de HTML CORS Handling Solicitudes Cross-Origin Configuración de Encabezados Configuración para Desarrollo ``` **Principio fundamental**: Las aplicaciones web modernas son sistemas de orquestación de datos: coordinan entre interfaces de usuario, APIs de servidor y modelos de seguridad del navegador para crear experiencias fluidas y responsivas. --- ## Entendiendo la Obtención de Datos en Aplicaciones Web Modernas La manera en que las aplicaciones web manejan datos ha evolucionado dramáticamente en las últimas dos décadas. Entender esta evolución te ayudará a apreciar por qué técnicas modernas como AJAX y la API Fetch son tan poderosas y por qué se han vuelto herramientas esenciales para los desarrolladores web. Exploremos cómo funcionaban los sitios tradicionales en comparación con las aplicaciones dinámicas y responsivas que construimos hoy. ### Aplicaciones Tradicionales de Múltiples Páginas (MPA) En los primeros días de la web, cada clic era como cambiar de canal en un televisor antiguo: la pantalla se quedaba en blanco, luego sintonizaba lentamente el nuevo contenido. Esta era la realidad de las primeras aplicaciones web, donde cada interacción significaba reconstruir toda la página desde cero. ```mermaid sequenceDiagram participant User participant Browser participant Server User->>Browser: Hace clic en enlace o envía formulario Browser->>Server: Solicita nueva página HTML Note over Browser: La página queda en blanco Server->>Browser: Devuelve página HTML completa Browser->>User: Muestra nueva página (destello/recarga) ``` ![Flujo de actualización en una aplicación de múltiples páginas](../../../../translated_images/es/mpa.7f7375a1a2d4aa77.webp) **Por qué este enfoque se sentía torpe:** - Cada clic significaba reconstruir toda la página desde cero - Los usuarios eran interrumpidos a mitad de una idea por esos molestos parpadeos de página - Tu conexión a internet trabajaba horas extras descargando el mismo encabezado y pie de página repetidamente - Las apps se sentían más como pasar páginas de un archivador que usar software ### Aplicaciones Modernas de Página Única (SPA) AJAX (JavaScript asíncrono y XML) cambió este paradigma por completo. Como el diseño modular de la Estación Espacial Internacional, donde los astronautas pueden reemplazar componentes individuales sin reconstruir toda la estructura, AJAX nos permite actualizar partes específicas de una página sin recargar todo. A pesar del nombre que menciona XML, hoy usamos principalmente JSON, pero el principio central sigue siendo el mismo: actualizar solo lo que necesita cambiar. ```mermaid sequenceDiagram participant User participant Browser participant JavaScript participant Server User->>Browser: Interactúa con la página Browser->>JavaScript: Dispara el manejador de eventos JavaScript->>Server: Obtiene solo los datos necesarios Server->>JavaScript: Devuelve datos JSON JavaScript->>Browser: Actualiza elementos específicos de la página Browser->>User: Muestra contenido actualizado (sin recargar) ``` ![Flujo de actualización en una aplicación de página única](../../../../translated_images/es/spa.268ec73b41f992c2.webp) **Por qué las SPA se sienten mucho mejor:** - Solo las partes que cambiaron realmente se actualizan (inteligente, ¿no?) - No más interrupciones chocantes: tus usuarios mantienen su flujo - Menos datos moviéndose por la red significa cargas más rápidas - Todo se siente ágil y responsivo, como las apps en tu teléfono ### La Evolución hacia la API Fetch Moderna Los navegadores modernos ofrecen la [`Fetch` API](https://developer.mozilla.org/docs/Web/API/Fetch_API), que reemplaza a la antigua [`XMLHttpRequest`](https://developer.mozilla.org/docs/Web/API/XMLHttpRequest/Using_XMLHttpRequest). Como la diferencia entre operar un telégrafo y usar correo electrónico, Fetch API usa promesas para un código asíncrono más limpio y maneja JSON de forma nativa. | Característica | XMLHttpRequest | Fetch API | |---------|----------------|----------| | **Sintaxis** | Callbacks complejos | Promesas limpias | | **Manejo JSON** | Requiere parseo manual | Método `.json()` integrado | | **Manejo de errores** | Información de error limitada | Detalles completos de error | | **Soporte moderno** | Compatibilidad legacy | Promesas ES6+ y async/await | > 💡 **Compatibilidad con navegadores**: Buenas noticias: la API Fetch funciona en todos los navegadores modernos. Si tienes curiosidad por versiones específicas, [caniuse.com](https://caniuse.com/fetch) tiene la información completa. > **En resumen:** - Funciona genial en Chrome, Firefox, Safari y Edge (prácticamente donde están tus usuarios) - Solo Internet Explorer necesita ayuda extra (y honestamente, ya es hora de dejarlo ir) - Te prepara perfectamente para los patrones elegantes de async/await que usaremos más adelante ### Implementando Inicio de Sesión y Recuperación de Datos Ahora implementemos el sistema de inicio de sesión que transforma tu app bancaria de una visualización estática a una aplicación funcional. Como los protocolos de autenticación usados en instalaciones militares seguras, verificaremos las credenciales del usuario y luego proporcionaremos acceso a sus datos específicos. Lo construiremos de manera incremental, comenzando con autenticación básica y luego añadiendo las capacidades para obtener datos. #### Paso 1: Crear la Base de la Función de Inicio de Sesión Abre tu archivo `app.js` y añade una nueva función `login`. Esta manejará el proceso de autenticación del usuario: ```javascript async function login() { const loginForm = document.getElementById('loginForm'); const user = loginForm.user.value; } ``` **Desglosemos esto:** - ¿La palabra clave `async`? Le dice a JavaScript "oye, esta función podría necesitar esperar cosas" - Estamos agarrando nuestro formulario de la página (nada fancy, solo buscándolo por su ID) - Luego extraemos lo que el usuario escribió como nombre de usuario - Aquí un truco: puedes acceder a cualquier entrada de formulario por su atributo `name` — ¡no necesitas más llamadas a getElementById! > 💡 **Patrón para acceso a formulario**: Cada control de formulario puede ser accedido por su nombre (establecido en HTML con el atributo `name`) como propiedad del formulario. Esto ofrece una manera limpia y legible de obtener datos del formulario. #### Paso 2: Crear la Función para Obtener Datos de Cuenta Luego, crearemos una función dedicada para recuperar los datos de la cuenta del servidor. Sigue el mismo patrón que tu función de registro pero se enfoca en obtener datos: ```javascript async function getAccount(user) { try { const response = await fetch('//localhost:5000/api/accounts/' + encodeURIComponent(user)); return await response.json(); } catch (error) { return { error: error.message || 'Unknown error' }; } } ``` **Esto es lo que logra este código:** - **Usa** la moderna API `fetch` para solicitar datos de manera asíncrona - **Construye** una URL para solicitud GET con el parámetro del nombre de usuario - **Aplica** `encodeURIComponent()` para manejar de forma segura caracteres especiales en URLs - **Convierte** la respuesta a formato JSON para fácil manipulación - **Maneja** errores elegantemente devolviendo un objeto de error en vez de fallar > ⚠️ **Nota de seguridad**: La función `encodeURIComponent()` maneja caracteres especiales en URLs. Como los sistemas de codificación usados en comunicaciones navales, asegura que tu mensaje llegue exactamente como quieres, evitando que caracteres como "#" o "&" sean malinterpretados. > **Por qué esto importa:** - Evita que caracteres especiales rompan las URLs - Protege contra ataques de manipulación de URLs - Asegura que tu servidor reciba los datos previstos - Sigue prácticas de codificación segura #### Entendiendo las Solicitudes HTTP GET Esto puede sorprenderte: cuando usas `fetch` sin opciones adicionales, crea automáticamente una solicitud [`GET`](https://developer.mozilla.org/docs/Web/HTTP/Methods/GET). Esto es perfecto para lo que hacemos: preguntarle al servidor "oye, ¿puedo ver los datos de la cuenta de este usuario?" Piensa en las solicitudes GET como pedir prestado un libro en la biblioteca de manera educada: estás pidiendo ver algo que ya existe. Las solicitudes POST (que usamos para el registro) son más como enviar un nuevo libro para añadir a la colección. | Solicitud GET | Solicitud POST | |-------------|-------------| | **Propósito** | Recuperar datos existentes | Enviar datos nuevos al servidor | | **Parámetros** | En la URL o query string | En el cuerpo de la solicitud | | **Cacheo** | Puede ser cacheado por navegadores | Normalmente no se cachea | | **Seguridad** | Visible en URL/logs | Oculto en cuerpo de la solicitud | ```mermaid sequenceDiagram participant B as Navegador participant S as Servidor Note over B,S: Solicitud GET (Recuperación de Datos) B->>S: GET /api/accounts/test S-->>B: 200 OK + Datos de la Cuenta Note over B,S: Solicitud POST (Envío de Datos) B->>S: POST /api/accounts + Datos de Nueva Cuenta S-->>B: 201 Created + Confirmación Note over B,S: Manejo de Errores B->>S: GET /api/accounts/nonexistent S-->>B: 404 Not Found + Mensaje de Error ``` #### Paso 3: Juntándolo Todo Ahora viene la parte satisfactoria: conectemos tu función de obtener cuenta con el proceso de inicio de sesión. Aquí es donde todo encaja: ```javascript async function login() { const loginForm = document.getElementById('loginForm'); const user = loginForm.user.value; const data = await getAccount(user); if (data.error) { return console.log('loginError', data.error); } account = data; navigate('/dashboard'); } ``` Esta función sigue una secuencia clara: - Extrae el nombre de usuario desde la entrada del formulario - Solicita los datos de cuenta del usuario desde el servidor - Maneja cualquier error que ocurra durante el proceso - Guarda los datos de la cuenta y navega al tablero al tener éxito > 🎯 **Patrón Async/Await**: Como `getAccount` es una función asíncrona, usamos la palabra clave `await` para pausar la ejecución hasta recibir respuesta del servidor. Esto evita que el código siga con datos indefinidos. #### Paso 4: Crear un Lugar para Tus Datos Tu app necesita un lugar para recordar la información de la cuenta una vez cargada. Piensa en esto como la memoria a corto plazo de tu app: un lugar para mantener a la mano los datos del usuario actual. Añade esta línea al inicio de tu archivo `app.js`: ```javascript // Esto contiene los datos de la cuenta del usuario actual let account = null; ``` **Por qué lo necesitamos:** - Mantiene los datos de la cuenta accesibles desde cualquier parte de tu app - Comenzar con `null` significa "nadie ha iniciado sesión todavía" - Se actualiza cuando alguien inicia sesión o se registra con éxito - Actúa como una fuente única de verdad: sin confusiones sobre quién está conectado #### Paso 5: Enlaza Tu Formulario Ahora conectemos tu nueva función de inicio de sesión con tu formulario HTML. Actualiza la etiqueta del formulario así: ```html
``` **Qué hace este pequeño cambio:** - Detiene que el formulario haga su comportamiento por defecto de "recargar toda la página" - Llama a tu función personalizada de JavaScript en su lugar - Mantiene todo suave y como una SPA (Single Page Application) - Te da control completo sobre qué pasa cuando los usuarios hacen clic en "Login" #### Paso 6: Mejora Tu Función de Registro Para mantener consistencia, actualiza tu función `register` para también guardar datos de cuenta y navegar al tablero: ```javascript // Agrega estas líneas al final de tu función register account = result; navigate('/dashboard'); ``` **Esta mejora proporciona:** - Transición **fluida** del registro al tablero - Experiencia **consistente** para el usuario entre flujos de inicio de sesión y registro - Acceso **inmediato** a datos de cuenta tras un registro exitoso #### Probando Tu Implementación ```mermaid flowchart TD A[El usuario introduce credenciales] --> B[Se llama a la función de inicio de sesión] B --> C[Obtener datos de la cuenta del servidor] C --> D{¿Datos recibidos correctamente?} D -->|Sí| E[Guardar datos de la cuenta globalmente] D -->|No| F[Mostrar mensaje de error] E --> G[Navegar al panel de control] F --> H[El usuario permanece en la página de inicio de sesión] ``` **Hora de ponerla a prueba:** 1. Crea una cuenta nueva para asegurarte que todo funciona 2. Intenta iniciar sesión con esas mismas credenciales 3. Observa la consola de tu navegador (F12) si algo parece raro 4. Asegúrate de aterrizar en el tablero tras un inicio de sesión exitoso Si algo no funciona, ¡no te preocupes! La mayoría de errores son correcciones simples como errores de tipeo o olvidar arrancar el servidor API. #### Una Rápida Palabra Sobre la Magia Cross-Origin Quizás te preguntes: "¿Cómo es que mi app web está hablando con este servidor API si corren en puertos diferentes?" ¡Buena pregunta! Esto toca algo que todo desarrollador web encuentra tarde o temprano. > 🔒 **Seguridad Cross-Origin**: Los navegadores aplican una "política de mismo origen" para evitar comunicación no autorizada entre diferentes dominios. Como un sistema de control en el Pentágono, verifican que la comunicación esté autorizada antes de permitir transferencia de datos. > **En nuestra configuración:** - Tu app web corre en `localhost:3000` (servidor de desarrollo) - Tu servidor API corre en `localhost:5000` (servidor backend) - El servidor API incluye [cabeceras CORS](https://developer.mozilla.org/docs/Web/HTTP/CORS) que autorizan explícitamente la comunicación desde tu app web Esta configuración refleja el desarrollo real donde frontend y backend suelen correr en servidores separados. > 📚 **Aprende más**: Profundiza en APIs y obtención de datos con este completo [módulo de Microsoft Learn sobre APIs](https://docs.microsoft.com/learn/modules/use-apis-discover-museum-art/?WT.mc_id=academic-77807-sagibbon). ## Dando Vida a Tus Datos en HTML Ahora haremos visibles los datos obtenidos para los usuarios a través de manipulación del DOM. Como el proceso de revelar fotografías en un cuarto oscuro, estamos tomando datos invisibles y convirtiéndolos en algo que los usuarios pueden ver e interactuar. La manipulación del DOM es la técnica que transforma páginas web estáticas en aplicaciones dinámicas que actualizan su contenido según las interacciones del usuario y las respuestas del servidor. ### Elegir la Herramienta Correcta para el Trabajo Cuando se trata de actualizar tu HTML con JavaScript, tienes varias opciones. Piensa en ellas como diferentes herramientas en una caja de herramientas, cada una perfecta para trabajos específicos: | Método | Para qué es ideal | Cuándo usarlo | Nivel de seguridad | |--------|-------------------|---------------|--------------------| | `textContent` | Mostrar datos del usuario de forma segura | Cada vez que muestres texto | ✅ Muy seguro | | `createElement()` + `append()` | Construir diseños complejos | Crear nuevas secciones/listas | ✅ A prueba de balas | | `innerHTML` | Establecer contenido HTML | ⚠️ Trata de evitar este | ❌ Negocio riesgoso | #### La Forma Segura de Mostrar Texto: textContent La propiedad [`textContent`](https://developer.mozilla.org/docs/Web/API/Node/textContent) es tu mejor aliada para mostrar datos del usuario. Es como tener un portero en tu página web: nada dañino pasa: ```javascript // La forma segura y confiable de actualizar texto const balanceElement = document.getElementById('balance'); balanceElement.textContent = account.balance; ``` **Beneficios de textContent:** - Trata todo como texto plano (evita la ejecución de scripts) - Limpia automáticamente el contenido existente - Eficiente para actualizaciones de texto simples - Proporciona seguridad integrada contra contenido malicioso #### Crear Elementos HTML Dinámicos Para contenido más complejo, combina [`document.createElement()`](https://developer.mozilla.org/docs/Web/API/Document/createElement) con el método [`append()`](https://developer.mozilla.org/docs/Web/API/ParentNode/append): ```javascript // Forma segura de crear nuevos elementos const transactionItem = document.createElement('div'); transactionItem.className = 'transaction-item'; transactionItem.textContent = `${transaction.date}: ${transaction.description}`; container.append(transactionItem); ``` **Comprendiendo este enfoque:** - **Crea** elementos DOM nuevos programáticamente - **Mantiene** control total sobre atributos y contenido del elemento - **Permite** estructuras complejas y anidadas de elementos - **Preserva** la seguridad al separar estructura de contenido > ⚠️ **Consideración de Seguridad**: Aunque [`innerHTML`](https://developer.mozilla.org/docs/Web/API/Element/innerHTML) aparece en muchos tutoriales, puede ejecutar scripts incrustados. Al igual que los protocolos de seguridad en CERN que previenen la ejecución no autorizada de código, usar `textContent` y `createElement` provee alternativas más seguras. > **Riesgos de innerHTML:** - Ejecuta cualquier etiqueta `