Este artículo es la tercera parte del articulo original (Segunda parte), en la cual hablamos de los HTTP Verbs, su importancia, funcionalidad y cómo implementarla en nuestro API utilizando NodeJS + Express. En esta tercera parte, hablaremos acerca de los URL paths, cómo es posible crear URL parametrizadas y la forma de recuperar los parámetros del objeto request.
URL Paths
Uno de los aspectos más importantes de un servicio REST, es su URL, primero que nada, porque es la forma en que podemos consumir el servicio, pero también es importante por le da al usuario una pista significativa acerca de su funcionalidad. Una URL bien definida, podría decirle al usuario para que sirve con una precisión muy acertada, sin tener que recurrir a la documentación.
Para que una URL tenga un significado real, es necesario complementarlo con método (o verb) al que responde, pues el método nos dice el tipo de operación que va a realizar, mientras que la URL nos dice que es lo que va hacer. Analicemos las siguientes URL:
GET | /users/oscar/avatar |
PUT | /users/oscar/avatar |
DELETE | /users/oscar |
POST | /users |
Quiero que te tomes solo un momento para analizar las URL anteriores… te aseguro que sin ser un experto pudiste adivinar con gran certeza que hace cada una de estas operaciones. Si no, te recomiendo ver la segunda parte de este artículo para refrescar un poco la memoria.
Como sea, vamos a explicar que hace cada una, en la primera URL, sabemos que el GET se utiliza para consultas y la URL habla de usuarios, luego un nombre y finalmente un avatar, por lo que podemos deducir que este servicio está realizando la consulta del Avatar del usuario oscar, ¿vez que fácil?
En la segunda URL, sabemos que PUT se utiliza para realizar updates, por lo tanto, le estamos diciendo que actualice el Avatar del usuario oscar.
En la tercera URL, sabemos que DELETE se utiliza para borrar un registro, por lo que está de más decir que lo que hace es borrar el usuario oscar.
En la cuarta URL, sabemos que POST se utiliza para crear un nuevo registro y está invocando solamente /users, esto me dice que el servicio está creando un nuevo usuario.
Con Express es realmente fácil implementar estas URL, tan solo hay que definir los Routers con el método adecuado y con el URL al que debe procesar, veamos cómo quedaría:
app.get('/users/oscar/avatar', (req, res) => { res.send('Hello GET:/users/oscar/avatar') }) app.put('/users/oscar/avatar', (req, res) => { res.send('Hello PUT:/users/oscar/avatar') }) app.delete('/users/oscar', (req, res) => { res.send('Hello DELETE:/users/oscar') }) app.post('/users', (req, res) => { res.send('Hello POST:/users') })
Los paths siempre deben de representar exactamente lo que hacen, y el método debe de corresponder con la acción que realizará, pues no hacerlo, puede confundir a los desarrolladores.
Prioridad de los paths
Un error al momento de iniciar con Express es pensar que el orden en que se definen los Routers es irrelevante, como si de una función se tratara, la cual puede ser llamada desde donde sea y siempre se ejecuta la correcta, sin embargo, esto no es cierto. Por este motivo, Express evaluar los Router en el orden en que están definidos.
Existe ocasiones en que más de una URL puede colisionar y entrar en el Path equivocado, por ejemplo, las siguientes dos URL:
GET: /*
GET:/login
La primera acepta cualquier URL, porque tiene un comodín (*), mientras que la segunda, solo acepta la URL /login. En este caso, como /* esta primero, entonces atenderá las peticiones que lleguen a /login, porque el path /* cumple con el patrón, en tal caso, tendríamos que invertir el orden de los Routers de la siguiente manera:
GET:/login
GET: /*
De esta forma, cuando llegue una petición a /login, la tomará el primer Router y para todos los demás path será /* quien procese la solicitud.
URL Params
Una de las características de REST, es la posibilidad de convertir ciertas partes de una URL en parámetro, de tal forma que nos ahorra tener que escribir una URL para cada registro que necesitemos.
Regresando al ejemplo de los servicios para usuarios GET: /users/oscar, podemos apreciar que “oscar” esta fija en la URL, lo que provocaría que tuviéramos que tener un Router para cada usuario registrado. Por suerte, Express nos permite escribir URL Params. Para convertir una sección de la URL en URL param, solo tendremos que anteponer dos puntos (:) antes, por ejemplo:
/users/:username
/users/:username/:field
En la primera URL podríamos recibir consultas para todos los usuarios, por ejemplo:
/users/oscar , /users/juan , /users/pedro
Mientras que en la segunda URL podríamos consultar cualquier campo del usuario, por ejemplo:
/users/oscar/avatar o /users/juan/banner
Para recuperar los URL Params, tan solo es necesario recuperarlos del objeto request de la siguiente manera: req.params.<name>. Veamos algunos ejemplos:
Query params
Los query params son lo más conocidas, y son todos aquellos que van al final de la URL seguido del símbolo de interrogación (?). Se pueden enviar cuantos Query params se requiere, siempre y cuando no excedamos el límite máximo de caracteres para un URL. Cada parámetro deberá está separado un el símbolo de ampersand (&). Algunos ejemplos:
/cources?coupon=FREE&Source=Google
Este tipo de parámetros es muy común en campañas publicitarias, pues el param coupon determina que el curso a comprar es gratis (free), mientras que el param Source nos dice de donde llego el cliente (google).
Para recuperar un Query param en Express se usa la siguiente sentencia, req.query.<parama-name>. Veamos cómo implementarlo en Express.
app.get('/cources', (req, res) => { var coupon = req.query.coupon var source = req.query.source res.send("Coupo: " + coupon + ", Source: " + source) })
Si ejecutamos la URL /cources?coupon=FREE&Source=Google obtendremos el siguiente resultado:
Body params
El tercer y último tipo de parámetro que podemos enviarle a un servicio REST, es el payload (o body), el cual puede ser un mensaje largo que no se puede ver a simple vista. No todos los métodos HTTP soportan el envío de un payload, por lo que hay que tener eso en cuenta.
De los métodos más utilizados que soportan el envío de un payload son: POST, PUT, PATCH, DELETE. Observa que el método GET no lo soporta.
Recuperar el body del request no está simple como parecería, pues en realidad, este parámetro es un InputStream, lo que quiere decir, que se recibe como los datos poco a poco y no todo de una. Esto nos obliga a procesar el payload a medida que va llegando. Este proceso lo podemos simplificar con ayuda del módulo body-parser, el cual instalamos en la primera parte de este artículo (npm install –save body-parser).
Mediante este módulo, es posible convertir el payload en varios formatos, pero el que nos interesa es JSON, pues es el estándar para REST. Configurarlo, solo tendremos que importarlo y agregar un middleware (los analizaremos más adelante).
Finalmente, existe una última forma de recibir información para el API, la cual es a través de Header, sin embargo, esta parte la dejaremos para la siguiente parte, en la cual hablaremos de la autenticación mediante JSON Web Tokens (JWT).
Enhorabuena por el post.
Gracias “JJ”?
Excelente Post, te da una buena visión de cómo empezar a desarrollar API Rest con NodeJS.
Que bueno que te agrado el post, si quieres seguir profundizando en el tema, te invito a que veas mi libro de aplicaciones reactivas con React, Nodejs &MongoDB. https://reactiveprogramming.io
Excelente paso a paso de construccion REST API. Les pido su amable colaboracion con el siguiente apunte:
tengo entendido que en un proyecto que involucra Frontend, API REST y BD, los tres pueden hospedarse en servidores separados. En un proyecto que estoy construyendo, los tres mencionados los tengo en el mismo servidor. Para la prueba en mi PC me funciona la API simple ejecucion en consola de “node apirest.js”, y frontend en el navegador. Pero para publicar en un servidor remoto no encuentro forma de arrancar la API. Le he construido un componente a manera de aplicacion en Angular pero no logro hacerlo funcionar. Puede darme ideas. Gracias por la valiosa colaboracion.
Hola Gilberto,
Lo que mencionas es correcto, los 3 componentes pueden estar en servidores independientes, todo dependerá de que arquitectura de servidores que funcione mejor, de la misma forma, puede tener los 3 juntos.
Con respecto a por que no te funciona en el servidor remoto, bueno… puede hacer cientos de motivos por el cual no funcione, y es imposible decirte sin saber nada del error que te lanza al ejecutarlo.
saludos.
Entendido Oscar, seguro no fui especifico en la pregunta. Me refiero puntuamente a la forma de inicializar la API; si localmente la puedo ejecutar con el comando node apirest.js, remotamente como lo haria?. En mi PC tengo instalado node, en el servidor remoto y teniendo en cuenta que es un hosting rentado, que necesitaria?. Definitivamente debe hacerse con un html? o conoce alguna otra forma de inicializar la api?
Gracias
Ok, ya te entiendo, pero en el servidor debería de ejecutarse de la misma forma (node apirest.js) ya intentaste hacerlo así?
Excelente tu aporte carnal! mucho muy digerible para cualquier persona. Muchas gracias y éxito!
Muchas gracias amigo, tambien puedes seguirnos en Youtube, allí cargamos subimos mucho contenido interesante: https://www.youtube.com/channel/UCaDtXOU301UgSghUuHwkelw
Que tal muy buen Post tocayo, pero ya no vi el link de la parte de autenticación con json web tokens y me interesa, saludos
Hola, te dejo dos link, el primero es la teoría que hay sobre la autenticación por tokens y el segundo es como implementar JWT en NodeJS
https://www.oscarblancarteblog.com/2017/06/08/autenticacion-con-json-web-tokens/
https://www.oscarblancarteblog.com/2018/01/16/implementar-json-web-tokens-nodejs/
como seria una estructura correcta de un proyecto en nodejs (API), por que veo muchos post que lo hacen de diferente manera,
Es que no existe una estructura correcta, es por eso la diferencia en muchas páginas, mi sugerencia es que organices los archivos como mejor te acomode
Excelente explicación ya tenia un buen buscando en la web hasta que encontre tu blog :D, espero la cuarta parte de header param 🙂
Gracias por el comentario Victor 🙂