# Construir una App Bancaria Parte 2: Crear un Formulario de Inicio de Sesión y Registro ## Cuestionario Previo a la Clase [Cuestionario previo a la clase](https://ff-quizzes.netlify.app/web/quiz/43) ### Introducción En casi todas las aplicaciones web modernas, puedes crear una cuenta para tener tu propio espacio privado. Como múltiples usuarios pueden acceder a una aplicación web al mismo tiempo, necesitas un mecanismo para almacenar los datos personales de cada usuario por separado y seleccionar qué información mostrar. No cubriremos cómo gestionar [la identidad del usuario de forma segura](https://en.wikipedia.org/wiki/Authentication), ya que es un tema extenso por sí solo, pero nos aseguraremos de que cada usuario pueda crear una (o más) cuentas bancarias en nuestra aplicación. En esta parte utilizaremos formularios HTML para añadir inicio de sesión y registro a nuestra aplicación web. Veremos cómo enviar los datos a una API de servidor de manera programada y, finalmente, cómo definir reglas básicas de validación para las entradas de usuario. ### Prerrequisitos Debes haber completado la lección de [plantillas HTML y enrutamiento](../1-template-route/README.md) de la aplicación web. También necesitas instalar [Node.js](https://nodejs.org) y [ejecutar la API del servidor](../api/README.md) localmente para poder enviar datos y crear cuentas. **Toma nota** Tendrás dos terminales ejecutándose al mismo tiempo, como se indica a continuación: 1. Para la aplicación bancaria principal que construimos en la lección de [plantillas HTML y enrutamiento](../1-template-route/README.md). 2. Para la [API del servidor de la aplicación bancaria](../api/README.md) que acabamos de configurar arriba. Necesitas que ambos servidores estén funcionando para seguir el resto de la lección. Están escuchando en diferentes puertos (puerto `3000` y puerto `5000`), por lo que todo debería funcionar correctamente. Puedes probar que el servidor está funcionando correctamente ejecutando este comando en una terminal: ```sh curl http://localhost:5000/api # -> should return "Bank API v1.0.0" as a result ``` --- ## Formulario y controles El elemento `
` encapsula una sección de un documento HTML donde el usuario puede ingresar y enviar datos mediante controles interactivos. Hay todo tipo de controles de interfaz de usuario (UI) que se pueden usar dentro de un formulario, siendo los más comunes los elementos `` y `
``` Usando el atributo `value` podemos definir un valor predeterminado para un input dado. También nota que el input para `balance` tiene el tipo `number`. ¿Se ve diferente a los otros inputs? Intenta interactuar con él. ✅ ¿Puedes navegar e interactuar con los formularios usando solo un teclado? ¿Cómo lo harías? ## Enviar datos al servidor Ahora que tenemos una interfaz funcional, el siguiente paso es enviar los datos al servidor. Hagamos una prueba rápida con nuestro código actual: ¿qué sucede si haces clic en el botón de *Inicio de Sesión* o *Registrar*? ¿Notaste el cambio en la sección de URL de tu navegador? ![Captura de pantalla del cambio en la URL del navegador después de hacer clic en el botón Registrar](../../../../translated_images/click-register.e89a30bf0d4bc9ca867dc537c4cea679a7c26368bd790969082f524fed2355bc.es.png) La acción predeterminada de un `
` es enviar el formulario a la URL actual del servidor usando el [método GET](https://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.3), añadiendo los datos del formulario directamente a la URL. Sin embargo, este método tiene algunas limitaciones: - Los datos enviados son muy limitados en tamaño (aproximadamente 2000 caracteres). - Los datos son directamente visibles en la URL (no es ideal para contraseñas). - No funciona con cargas de archivos. Por eso puedes cambiarlo para usar el [método POST](https://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.5), que envía los datos del formulario al servidor en el cuerpo de la solicitud HTTP, sin ninguna de las limitaciones anteriores. > Aunque POST es el método más comúnmente utilizado para enviar datos, [en algunos escenarios específicos](https://www.w3.org/2001/tag/doc/whenToUseGet.html) es preferible usar el método GET, como al implementar un campo de búsqueda. ### Tarea Añade las propiedades `action` y `method` al formulario de registro: ```html ``` Ahora intenta registrar una nueva cuenta con tu nombre. Después de hacer clic en el botón *Registrar*, deberías ver algo como esto: ![Una ventana del navegador en la dirección localhost:5000/api/accounts, mostrando una cadena JSON con datos de usuario](../../../../translated_images/form-post.61de4ca1b964d91a9e338416e19f218504dd0af5f762fbebabfe7ae80edf885f.es.png) Si todo va bien, el servidor debería responder a tu solicitud con una respuesta [JSON](https://www.json.org/json-en.html) que contiene los datos de la cuenta que se creó. ✅ Intenta registrarte nuevamente con el mismo nombre. ¿Qué sucede? ## Enviar datos sin recargar la página Como probablemente notaste, hay un pequeño problema con el enfoque que acabamos de usar: al enviar el formulario, salimos de nuestra aplicación y el navegador redirige a la URL del servidor. Estamos tratando de evitar todas las recargas de página con nuestra aplicación web, ya que estamos creando una [Aplicación de Página Única (SPA)](https://en.wikipedia.org/wiki/Single-page_application). Para enviar los datos del formulario al servidor sin forzar una recarga de página, tenemos que usar código JavaScript. En lugar de poner una URL en la propiedad `action` de un elemento ``, puedes usar cualquier código JavaScript precedido por la cadena `javascript:` para realizar una acción personalizada. Usar esto también significa que tendrás que implementar algunas tareas que anteriormente se hacían automáticamente por el navegador: - Recuperar los datos del formulario. - Convertir y codificar los datos del formulario a un formato adecuado. - Crear la solicitud HTTP y enviarla al servidor. ### Tarea Reemplaza la propiedad `action` del formulario de registro con: ```html ``` Abre `app.js` y añade una nueva función llamada `register`: ```js function register() { const registerForm = document.getElementById('registerForm'); const formData = new FormData(registerForm); const data = Object.fromEntries(formData); const jsonData = JSON.stringify(data); } ``` Aquí recuperamos el elemento del formulario usando `getElementById()` y utilizamos el ayudante [`FormData`](https://developer.mozilla.org/docs/Web/API/FormData) para extraer los valores de los controles del formulario como un conjunto de pares clave/valor. Luego convertimos los datos a un objeto regular usando [`Object.fromEntries()`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object/fromEntries) y finalmente serializamos los datos a [JSON](https://www.json.org/json-en.html), un formato comúnmente utilizado para intercambiar datos en la web. Los datos ahora están listos para ser enviados al servidor. Crea una nueva función llamada `createAccount`: ```js async function createAccount(account) { try { const response = await fetch('//localhost:5000/api/accounts', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: account }); return await response.json(); } catch (error) { return { error: error.message || 'Unknown error' }; } } ``` ¿Qué hace esta función? Primero, nota la palabra clave `async` aquí. Esto significa que la función contiene código que se ejecutará [**asíncronamente**](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Statements/async_function). Cuando se usa junto con la palabra clave `await`, permite esperar a que se ejecute el código asíncrono, como esperar la respuesta del servidor aquí, antes de continuar. Aquí hay un video rápido sobre el uso de `async/await`: [![Async y Await para gestionar promesas](https://img.youtube.com/vi/YwmlRkrxvkk/0.jpg)](https://youtube.com/watch?v=YwmlRkrxvkk "Async y Await para gestionar promesas") > 🎥 Haz clic en la imagen de arriba para ver un video sobre async/await. Usamos la API `fetch()` para enviar datos JSON al servidor. Este método toma 2 parámetros: - La URL del servidor, por lo que volvemos a poner `//localhost:5000/api/accounts` aquí. - La configuración de la solicitud. Ahí es donde configuramos el método como `POST` y proporcionamos el `body` para la solicitud. Como estamos enviando datos JSON al servidor, también necesitamos establecer el encabezado `Content-Type` como `application/json` para que el servidor sepa cómo interpretar el contenido. Como el servidor responderá a la solicitud con JSON, podemos usar `await response.json()` para analizar el contenido JSON y devolver el objeto resultante. Nota que este método es asíncrono, por lo que usamos la palabra clave `await` aquí antes de devolver para asegurarnos de que cualquier error durante el análisis también sea capturado. Ahora añade algo de código a la función `register` para llamar a `createAccount()`: ```js const result = await createAccount(jsonData); ``` Debido a que usamos la palabra clave `await` aquí, necesitamos añadir la palabra clave `async` antes de la función register: ```js async function register() { ``` Finalmente, añadamos algunos logs para verificar el resultado. La función final debería verse así: ```js async function register() { const registerForm = document.getElementById('registerForm'); const formData = new FormData(registerForm); const jsonData = JSON.stringify(Object.fromEntries(formData)); const result = await createAccount(jsonData); if (result.error) { return console.log('An error occurred:', result.error); } console.log('Account created!', result); } ``` ¡Eso fue un poco largo, pero lo logramos! Si abres las [herramientas de desarrollo del navegador](https://developer.mozilla.org/docs/Learn/Common_questions/What_are_browser_developer_tools) e intentas registrar una nueva cuenta, no deberías ver ningún cambio en la página web, pero aparecerá un mensaje en la consola confirmando que todo funciona. ![Captura de pantalla mostrando un mensaje de log en la consola del navegador](../../../../translated_images/browser-console.efaf0b51aaaf67782a29e1a0bb32cc063f189b18e894eb5926e02f1abe864ec2.es.png) ✅ ¿Crees que los datos se envían al servidor de forma segura? ¿Qué pasaría si alguien pudiera interceptar la solicitud? Puedes leer sobre [HTTPS](https://en.wikipedia.org/wiki/HTTPS) para saber más sobre la comunicación segura de datos. ## Validación de datos Si intentas registrar una nueva cuenta sin establecer primero un nombre de usuario, puedes ver que el servidor devuelve un error con el código de estado [400 (Solicitud Incorrecta)](https://developer.mozilla.org/docs/Web/HTTP/Status/400#:~:text=The%20HyperText%20Transfer%20Protocol%20(HTTP,%2C%20or%20deceptive%20request%20routing).). Antes de enviar datos a un servidor, es una buena práctica [validar los datos del formulario](https://developer.mozilla.org/docs/Learn/Forms/Form_validation) de antemano cuando sea posible, para asegurarte de enviar una solicitud válida. Los controles de formulario HTML5 proporcionan validación integrada usando varios atributos: - `required`: el campo necesita ser llenado, de lo contrario el formulario no puede ser enviado. - `minlength` y `maxlength`: define el número mínimo y máximo de caracteres en campos de texto. - `min` y `max`: define el valor mínimo y máximo de un campo numérico. - `type`: define el tipo de datos esperado, como `number`, `email`, `file` u [otros tipos integrados](https://developer.mozilla.org/docs/Web/HTML/Element/input). Este atributo también puede cambiar la representación visual del control del formulario. - `pattern`: permite definir un patrón de [expresión regular](https://developer.mozilla.org/docs/Web/JavaScript/Guide/Regular_Expressions) para verificar si los datos ingresados son válidos o no. > Consejo: puedes personalizar el aspecto de tus controles de formulario dependiendo de si son válidos o no utilizando las pseudo-clases CSS `:valid` y `:invalid`. ### Tarea Hay 2 campos obligatorios para crear una nueva cuenta válida: el nombre de usuario y la moneda. Los demás campos son opcionales. Actualiza el HTML del formulario, utilizando tanto el atributo `required` como texto en la etiqueta del campo para que: ```html ... ``` Aunque esta implementación particular del servidor no impone límites específicos en la longitud máxima de los campos, siempre es una buena práctica definir límites razonables para cualquier entrada de texto del usuario. Agrega un atributo `maxlength` a los campos de texto: ```html ... ... ``` Ahora, si presionas el botón *Registrar* y un campo no cumple con una regla de validación que definimos, deberías ver algo como esto: ![Captura de pantalla que muestra el error de validación al intentar enviar el formulario](../../../../translated_images/validation-error.8bd23e98d416c22f80076d04829a4bb718e0e550fd622862ef59008ccf0d5dce.es.png) La validación como esta, realizada *antes* de enviar cualquier dato al servidor, se llama validación **del lado del cliente**. Pero ten en cuenta que no siempre es posible realizar todas las verificaciones sin enviar los datos. Por ejemplo, aquí no podemos comprobar si ya existe una cuenta con el mismo nombre de usuario sin enviar una solicitud al servidor. La validación adicional realizada en el servidor se llama validación **del lado del servidor**. Por lo general, ambas deben implementarse, y aunque usar la validación del lado del cliente mejora la experiencia del usuario al proporcionar retroalimentación instantánea, la validación del lado del servidor es crucial para asegurarse de que los datos del usuario que manipulas sean correctos y seguros. --- ## 🚀 Desafío Muestra un mensaje de error en el HTML si el usuario ya existe. Aquí tienes un ejemplo de cómo podría verse la página de inicio de sesión final después de un poco de diseño: ![Captura de pantalla de la página de inicio de sesión después de agregar estilos CSS](../../../../translated_images/result.96ef01f607bf856aa9789078633e94a4f7664d912f235efce2657299becca483.es.png) ## Cuestionario posterior a la lección [Cuestionario posterior a la lección](https://ff-quizzes.netlify.app/web/quiz/44) ## Revisión y autoestudio Los desarrolladores se han vuelto muy creativos en sus esfuerzos por construir formularios, especialmente en lo que respecta a estrategias de validación. Aprende sobre diferentes flujos de formularios explorando [CodePen](https://codepen.com); ¿puedes encontrar algunos formularios interesantes e inspiradores? ## Asignación [Estiliza tu aplicación bancaria](assignment.md) --- **Descargo de responsabilidad**: Este documento ha sido traducido utilizando el servicio de traducción automática [Co-op Translator](https://github.com/Azure/co-op-translator). Si bien nos esforzamos por lograr precisión, tenga en cuenta que las traducciones automáticas pueden contener errores o imprecisiones. El documento original en su idioma nativo debe considerarse como la fuente autorizada. Para información crítica, se recomienda una traducción profesional realizada por humanos. No nos hacemos responsables de malentendidos o interpretaciones erróneas que puedan surgir del uso de esta traducción.