![](https://i.imgur.com/ld6aL74.png =200x) # Express | Método POST - Peticiones en el `body` ## Introducción Las aplicaciones web simples funcionan con una comunicación unidireccional desde el navegador al servidor. El navegador emite una solicitud y el servidor devuelve un recurso (HTML, CSS, js). Esto es lo que llamamos solicitudes "GET". Puede pensar en las solicitudes `GET` como una solicitud HTTP en la que desea *obtener* algo. En esta lección, aprenderemos cómo enviar datos desde el navegador al servidor y cómo el servidor recibe esos parámetros y los usa para realizar operaciones. ### Introducción al método `POST` Cuando navegamos, continuamente realizamos solicitudes desde el navegador al servidor. La mayoría de las solicitudes serán solicitudes GET (es decir, dame este HTML/CSS/imágenes) ... pero a veces necesitamos enviar datos al servidor: - Para crear una cuenta de usuario - Agregar un nuevo tweet - Actualización del perfil de LinkedIn Estas acciones tienen algo en común: **envían datos para crear o actualizar recursos en el servidor.** HTML nos ofrece dos formas en las que podemos realizar solicitudes: `GET` y `POST`. :::info En realidad, HTTP define varios métodos de solicitud pero en el navegador, sin el uso de Javascript, solo podemos usar dos de ellos: `GET` y `POST`. Cuando solicitamos un recurso (http://example.com/image.png), el navegador realiza una solicitud `GET` al servidor con esa URL. Podemos enviar información a través de la cadena de consulta al final de la URL (https://dummyimage.com/200x300?text=sent-via-query-string) pero la cantidad y complejidad de los datos que podemos enviar a través de este método es muy limitado. Para enviar más información, o para evitar que la información se muestre en la barra de direcciones del navegador y se almacene en el historial del navegador, necesitamos usar formularios html para enviar los datos en el cuerpo de una solicitud `POST`. ::: Cuando solicitamos un recurso (http://example.com/image.png), creará implícitamente una solicitud `GET` al servidor con esa URL. No obstante, aquí no enviamos ninguna información. Para enviar la información, normalmente necesitamos usar [formularios html](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/form). Veamos un ejemplo: ```htmlmixed= <!-- Simple form which will send a GET request --> <form action="example.com/user-data"> <label for="first-name-input">Nombre:</label> <input id="first-name-input" type="text" name="firstName"> <input type="submit" value="Save Name"> </form> ``` Si escribimos "Juan" en el campo de entrada y enviamos este formulario, el navegador generará una nueva solicitud para: ``` http://example.com/user-data?firstName=Juan ``` Y luego el servidor podrá identificar la ruta `/user-data` y extraer todos los parámetros enviados después de `?`, Como `firstName=Juan` en el ejemplo anterior. Este enfoque funciona y, a veces, es útil, pero existen dos problemas/limitaciones principales con el uso de `GET`: 1. No podemos enviar grandes parámetros con GET (como una foto, por ejemplo). 2. La información confidencial (contraseñas) se almacenará en el historial de su navegador y estará visible. Debido a esto, `POST` se inventó como un método alternativo para enviar datos al servidor: ```htmlmixed= <!-- Simple form which will send a POST request --> <form action="example.com/user-data" method="post"> <label for="first-name-input">Nombre:</label> <input id="first-name-input" type="text" name="firstName"> <input type="submit" value="Save Name"> </form> ``` Si escribimos "Juan" en el campo de entrada y enviamos este formulario, el navegador generará una nueva solicitud para: ``` http://example.com/user-data ``` Esta vez, `firstName=Juan` no estará en la URL, sino que el navegador agregará todos los parámetros del formulario como parte de la solicitud HTTP que enviamos al servidor. En esta lección, vamos a practicar el envío de parámetros `GET` y `POST` desde HTML, cómo recibirlos en el servidor y enviar una respuesta. Pero antes de entrar en eso, veamos algunas diferencias entre `GET` y `POST`: | CATEGORÍA | GET | POST |:--------:|-----|-------- | **Método HTTP** | Corresponde al verbo [HTTP GET](https://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.3) | Corresponde al verbo [HTTP POST](https://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.5) | **Cuándo utilizar** | Obtener datos | Actualizar/crear datos | **Método del formulario** | `<form method="get">` | `<form method="post">` | **Datos del formulario** | Campos anexados a la URL de acción con un '?' | Campos incluidos en el cuerpo del formulario y enviados al servidor | **Historial** | Los parámetros permanecen en el historial del navegador porque forman parte de la URL | Los parámetros no se guardan en el historial del navegador | **Marcar como favorito** | Se puede marcar como favorito | No se puede marcar como favorito | **Privacidad** | El método `GET` no debe utilizarse al enviar contraseñas u otra información confidencial | El método `POST` se utiliza al enviar contraseñas u otra información confidencial | **Visibilidad** | El método GET es visible para todos (se mostrará en la barra de direcciones del navegador) y tiene límites en la cantidad de información para enviar | Las variables del método POST no se muestran en la URL ## Parámetros (Params) ### Parámetros de consulta | Formulario con el método `GET` Como se discutió anteriormente, cuando creamos un formulario, por defecto hace un `GET`, y agrega los parámetros a nuestra URL, así ```htmlmixed= <!-- Simple form which will send a GET request --> <form action="example.com/user-data"> <label for="first-name-input">Nombre:</label> <input id="first-name-input" type="text" name="firstName"> <input type="submit" value="Save Name"> </form> ``` ``` http://example.com/user-data?firstName=Juan ``` Nuestra tarea es recopilar la información de nuestro usuario y mostrarla en otra página. Por ahora, obtendremos su nombre, edad y superhéroe favorito. #### Paso 1 | Mostrar un formulario Primero, necesitamos una ruta para mostrar una nueva vista. A esta ruta lo llamaremos "get-user-info": ```javascript /* app.js */ app.get('/get-user-info', (req, res) => { res.render('user-info-form'); }); ``` Luego, debemos crear una vista llamada `user-info-form`: `$ touch views/user-info-form.hbs` Y mostrar el formulario, con todos sus campos: ```htmlmixed <!-- user-info-form.hbs --> <form action="/display-user-info"> <label for="name-input">Name</label> <input id="name-input" type="text" name="name"> <label for="age-input">Age</label> <input id="age-input" type="number" name="age"> <label for="superhero-input">Favorite Superhero</label> <input id="superhero-input" type="text" name="superhero"> <button type="submit">Submit Info!</button> </form> ``` :::info :bulb: Se pueden utilizar `<button type="submit">` o `<input type="submit">` como botones de envío. ::: ##### input `type` El atributo `type` del input le permite al formulario saber cuál será la entrada. **Todos los valores se enviarán como una cadena**, pero el `type` puede cambiar el aspecto de algunas entradas. Todos los tipos de entrada se pueden encontrar [aquí](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input) en MDN. ##### input `id` El atributo `id` está en la etiqueta. La etiqueta `for` se adjunta al `id` del `input`. :::info :zap: Esto hace que si hace clic en el `label`, el `inpiut` hará `focus`. ::: ##### input `name` El `name` es el atributo más importante en el `input`. Así es como enviamos información desde el formulario al servidor. #### Paso 2 | Usar el parámetro de consulta El formulario está haciendo una solicitud `GET` a una ruta llamada` display-user-info`, por lo que tenemos que crear una ruta para manejar esa información y hacer algo con ella. ```javascript app.get('/display-user-info', (req, res) => { }); ``` Entonces, podemos acceder a la información a través de `req.query`: ```javascript app.get('/display-user-info', (req, res) => { let name = req.query.name; let age = req.query.age; let superhero = req.query.superhero; res.send(` Your name is ${name} Your age is ${age} Your favorite superhero is ${superhero} `) }); ``` ¿Qué sucedió? Nuestro formulario tomó todos nuestros campos de entrada y los agregó como `query parameters`. ![](https://i.imgur.com/kDXpTya.png) Eso significa que luego podemos acceder a esos datos en la ruta que recibe la solicitud en el servidor. Pero, ¿qué sucede cuando tenemos información confidencial que no queremos que se muestre en la barra de URL o que el usuario pueda manipularla fácilmente? ### Parámetros de formulario | Método `POST` Creemos nuestra primera solicitud `POST`. A menudo, con una solicitud `POST`, nuestro flujo se verá así: ```flow st=>start: Mostrar el formulario al usuario op=>operation: El usuario ingresa los datos en el formulario op2=>operation: El usuario envía los datos op3=>operation: El formulario hace una petición POST op4=>operation: El servidor intenta hacer login op4=>operation: El usuario es redirigido (a la home page, newsfeed, etc) e=>end: Termina st->op->op2->op3->op4->end ``` #### Paso 1 | Mostrar un formulario Creemos una nueva ruta, esto mostrará un formulario al usuario: ```javascript app.get('/login', (req, res) => { res.render('login') }); ``` Como habrás notado, estamos renderizando "login". Debemos crear `login.hbs`: ``` $ touch views/login.hbs ``` Y dentro del `login.hbs`, creamos nuestro primer formulario: ```htmlmixed <form action="/login" method="POST"> </form> ``` ##### Método El *método* es lo que le dice a nuestro formulario que haga una solicitud `POST`. Cuando creamos un formulario de inicio de sesión o enviamos alguna información, siempre debemos usar un "POST". Esto evita que el usuario vuelva a enviar información y es la semántica adecuada. #### Form cont. ```htmlmixed <form action="/login" method="POST"> <label for="email">Email</label> <input id="email" type="text" name="email"> <label for="password">Password</label> <input id="password" type="password" name="password"> <button type="submit"> Login </button> </form> ``` Hacemos click en `submit`! ¿Qué pasa? #### Paso 2 | La ruta `POST` En el ejemplo anterior, obtenemos un **404** porque no tenemos una ruta con un método de `POST` y una acción de`/login`. ¡Vamos a crearlo! ```javascript app.post('/login', (req, res) => { res.send('You\'ve logged in!'); }); ``` Espera un segundo ... ¡nunca iniciamos sesión! ¿Cómo accedemos a la información que el usuario ingresó en el formulario en el servidor? ##### Las peticiones en el `Body` / `Parámetros` `req` contiene información sobre la solicitud, incluido el correo electrónico y la contraseña que el usuario ingresó en el formulario. Desafortunadamente, estos datos no se pueden leer de forma predeterminada en Express con una solicitud `POST`. *Necesitamos el, [`bodyParser`](https://github.com/expressjs/body-parser)*! Primero, instalamos `bodyParser`: ``` $ npm install --save body-parser ``` Después, agregamos a nuestro archivo: ```javascript // ... const bodyParser = require('body-parser'); // ... app.use(bodyParser.urlencoded({ extended: true })); ``` `bodyparser` hace precisamente eso. Analiza el `body` de nuestra solicitud y nos lo da en el `req.body`: ```javascript app.post('/login', (req, res) => { res.send(req.body); }); ``` Ahora tenemos un objeto JavaScript simple con el que interactuar! ```javascript app.post('/login', (req, res) => { let email = req.body.email; let password = req.body.password; res.send(`Email: ${email}, Password: ${password}`); }); ``` ¿Que pasó aquí? Nuestro formulario envía sus datos en el cuerpo de la solicitud al servidor. `bodyParser` lo captura y lo convierte en un objeto JavaScript: ![](https://i.imgur.com/lS3106c.png) **Ejercicio** Agregamos un poco de lógica a nuestra ruta `post`. Si el email es `ucom@gmail.com` y la contraseña es`password`, mostramos un mensaje que dice "Bienvenido"; de lo contrario, mostramos un mensaje que diga "Adiós". **Código inicial** ```javascript app.post('/login', (req, res) => { // What ES6 feature could we use to clean these two lines up? let email = req.body.email; let password = req.body.password; if (/* fill in this condition*/){ // render "Welcome" } else { // render go away } }); ``` ## Middleware Cuando se realiza una solicitud a nuestro servidor Express, en realidad no va directamente a la ruta. Muchas veces, nuestra ruta es en realidad la última parada. Hemos utilizado un par de paquetes hasta ahora, incluido `bodyParser`. Estos paquetes se denominan *Middlewares*. > El término middleware se utiliza para describir productos separados que sirven como pegamento entre dos aplicaciones. > > El middleware a veces se denomina `cañería` porque conecta dos lados de una aplicación y pasa datos entre ellos. En este caso, los dos lados de la aplicación consisten en (1) el cliente que realiza una solicitud y (2) el servidor que maneja esa solicitud. El siguiente diagrama ilustra cómo nuestra aplicación maneja realmente una solicitud. ![Express App Requests](https://i.imgur.com/AO6lw3m.png) 1. La petición pasa por `cookieParser` 2. La petición pasa por `bodyParser` 3. La petición pasa por `logger` 4. La petición pasa por `authentication` 5. Finalmente, nuestra solicitud llega a nuestra ruta y devuelve la llamada. ¿Como funciona esto? Creemos un ejemplo simple para ilustrar esto. Primero, creemos una ruta de prueba: ```javascript app.get('/test', (req, res) => { res.send("We made it to test!"); }); ``` Entonces, creemos nuestro propio middleware : ```javascript // ... app.use(myFakeMiddleware) // ... function myFakeMiddleware(){ console.log("myFakeMiddleware was called!"); } ``` Hacemos una petición a `localhost:3000/test`: ![](https://i.imgur.com/Lnqfi8P.png) ¡Pero el navegador no carga nada! ¿Por qué? ### El patron de los `Middleware` `app.use()` es una función que agrega un middleware a nuestra pila de middlewares. Todos los middlewares se llaman, uno tras otro, y finalmente terminan con la ruta. El problema es que no estamos llamando a nuestro próximo middleware. La cadena está rota y hay una obstrucción en la tubería. Las funciones que funcionan como middlewares reciben 2-4 argumentos y uno de ellos es siempre el *next()* middleware que debemos llamar. Agreguemos eso a nuestra función: ```javascript function myFakeMiddleware(_, _, next){ console.log("myFakeMiddleware was called!"); next(); } ``` Pasamos `next` como nuestro tercer argumento, luego, cuando nuestro middleware termina de registrar, lo llamamos. Visitamos `localhost:3000/test`. #### Pasando información A menos que simplemente estemos registrando la solicitud, muchas veces necesitaremos pasar información a través de nuestro middleware. Express sugiere adjuntar cualquiera de sus datos al objeto `request`. Esto estará disponible en todos los middleware y en la ruta. Echemos un vistazo a este ejemplo de `middleware` falso: ```javascript function myFakeMiddleware(req, _, next){ console.log("myFakeMiddleware was called!"); req.secretValue = "swordfish"; next(); } ``` Después de llamar a nuestro middleware `myFakeMiddleware`, podemos acceder fácilmente al objeto *req*. En este ejemplo, podemos acceder a `secretValue`: ```javascript app.get('/test', (req, res) => { let mySecret = req.secretValue; res.send(mySecret); }); ``` Muchas veces no diseñaremos un middleware propio, Express ya tiene un [enorme ecosistema de middlewares](https://expressjs.com/en/resources/middleware.html), pero es muy útil comprender cómo se procesa la solicitud. Existen algunos paquetes de Node extremadamente útiles (algunos de los cuales son middlewares) que lo ayudarán a desarrollar aplicaciones. ## Apuntes finales Observe que el `GET` y` POST` tienen el mismo nombre de ruta, `/login`. Esto está bien porque el **método** los convierte en *dos rutas completamente diferentes*. Cuando hacemos la solicitud `GET`, se mostrará un formulario. Cuando el formulario realiza una solicitud `POST`, se enviará para realizar la lógica de inicio de sesión. ## Recursos extra - [body-parser Docs](https://github.com/expressjs/body-parser) - [Anatomy of an HTTP request in Node](https://nodejs.org/en/docs/guides/anatomy-of-an-http-transaction/)