Node.js: REST con Express
En este capitulo utilizaremos Express, un servidor HTTP construído sobre node.js, para comenzar a diagramar la API de nuestra aplicación de noticias.
Instalando Express
De la misma forma que procedimos con babel instalaremos los modulos pertenecientes a express.
npm install express -—save
En este caso utilizaremos el flag --save
en lugar de --save-dev
para indicar que se trata de una dependencia de la cual nuestro código hará uso explicito (no es una herramienta externa usada para desarrollo)
Ejecutando Express
Editaremos una vez más el codigo de nuestro archivo index.js
. El mismo ahora se encargará de inicializar express y escuchar en un puerto determinado.
index.js
Con la línea
import express from 'express'
estamos importando una función llamadaexpress
del modulo javascript homónimo. En caso de no especificarse nada los modulos serán buscados por node.js dentro del directorionode_modules
el cuál es creado y mantenido por npm (y no debe ser versionado)Dicha función
express
al ser invocada retornará un nuevo objeto el cual llamamosapp
. A travéz del mismo procederemos a configurar nuestra aplicación REST.A continuación bindeamos dicha aplicación al puerto
3001
por medio del métodolisten
. La función que proveemos al mismo es un callback que será invocado una vez que el binding se haya realizado correctamente (listen
se ejecuta de forma asincrónica)
Ahora, al ejecutar npm start
podremos ver como se instancia y se mantiene corriendo el servidor de express.
$ npm start
> [email protected] start /development/noticias-unq
> babel-node -- index.js
Server running on port 3001
Sin embargo es normal que al tratar de acceder mediante el browser a la URL http://localhost:3001 nos encontraremos con un error Cannot GET /.
Configurando rutas
El error anterior sucede porque en ningún momento instruímos a express sobre cómo debe responder ante cada petición HTTP.
Hello world
Comenzaremos creando una ruta la cual recibirá los parámetros HTTP que le envíeemos y responderá con un saludo. Para eso utilizaremos el objeto app
que habíamos obtenido anteriormente, de la siguiente forma:
index.js
Notemos que una ruta asocia un método HTTP que está definido por el método del objeto app
invocado (app.get(...)
en este caso), una url ('/greet'
) y una función handler ((req, res) => { ... }
) la cual define el comportamiento a utilizarse.
A la función handler se le proveeran dos paramétros: req
el cual modela el pedido hecho por el usuario con toda la información envíada (headers, body y parámetros); y res
la cual modela la respuesta sobre la cual información podrá ser devuelta al cliente.
Tras reiniciar node.js e invocar la siguiente url http://localhost:3001/greet?nombre=SeniorThompson obtendremos finalmente una respuesta!
Definiendo la API
Hablamos poco de lo que deseamos desarrollar pero la idea es que un usuario pueda hacer las siguientes acciones con la aplicación:
- Ver todas los noticias publicadas.
- Publicar una nueva noticia.
- Hacer un comentario en una noticia existente.
- Hacer upvote en una noticia.
- Hacer upvote en un comentario
Estas acciones pueden ser mapeadas directamente a varias rutas:
GET /noticias
- para retornar todas las noticias publicadas.POST /noticias
- para publicar una nueva noticia.GET /noticias/:id
- para retornar información de una noticia en particular con todos sus comentarios. La noticia será identificada por su identificador:id
.POST /noticias/:id/comentarios
- para agregar un nuevo comentario a una noticia.PUT /noticias/:id/upvote
- para hacer upvote en una noticia.PUT /noticias/:id/comentarios/:idComentario/upvote
- para hacer upvote en un comentario identificado por:idComentario
Almacenando y recuperando noticias
Vamos a crear las dos primeras rutas para recuperar todas las noticias existentes y publicar una nueva noticia.
Comenzaremos creando la estructura para ambas rutas:
index.js
Dado a que todavía no contamos con una base de datos donde guardar las noticias de momento las almacenaremos en un array global.
index.js
Envíando y recibiendo JSON
Por medio de res.json(noticias)
estamos serializando el objeto referenciado por noticias en formato JSON y envíandolo al cliente en el cuerpo de la repsuesta.
Por otro lado, al hacer let noticia = req.body
queremos hacer exactamente lo opuesto. request.body
debería referenciar al objeto JSON que el cliente envíe dentro del cuerpo de su pedido HTTP.
Para que esto último funcione deberemos configurar un middleware en expressjs. Un middleware es un función que se ejecutará antes de ejecutarse el código de cada ruta. Los middleware tienen acceso a los objetos request y response y pueden inyectar comportamiento antes de delegar al siguiente middleware en la cadena de responsabilidad.
Existe un middleware llamado body-parser el cual agrega a expressjs el comportamiento de parsear el contenido del cuerpo de la request HTTP antes de que se resuelva cada ruta y colocar el resultado de dicho parseo en el atributo req.body
Procederemos entonces a instalar body-parser en nuestra aplicación:
npm install body-parser -—save
Luego deberemos configurar express para que use body-parser para parsear los pedidos de tipo JSON (osea, aquellos que contienen el header Content-Type: application/json
)
index.js
Por medio de import bodyParser from 'bodyparser'
importamos el export del modulo bodyParser
en la variable del mismo nombre.
De acuerdo a la documentación dicho objeto (ahora referenciado por bodyParser) expone una serie de factories para crear middlewares. bodyParser.json()
construye justamente una función middleware para parsear cuerpos de tipo JSON.
Por medio de app.use( middleware )
configuramos en express una función middleware que será ejecutada para todos los pedidos que el servidor expressjs reciba.
Hasta acá logramos:
- Bindear un servidor expressjs al puerto 3001
- Configurar dos rutas (
GET /posts
yPOST /posts
) - Configurar un middleware (body-parser) para que extienda expressjs agregando la responsabilidad de parsear el contenido de los cuerpos HTTP
- Construir noticias a partir de los objetos recibidos y persistirlas temporalmente en un array.
GitHub
El código del ejemplo, hasta este punto, en Github.
Uso del ejemplo
Es muy importante usar este código solo como referencia. Por favor, evitar el copy-paste (ya que el objetivo es que cada uno vaya creando su propia versión personalizada y aprendiendo paso a paso)
Probando nuestra aplicación
Primero deberemos ejecutar nuestro servidor node (en caso de que ya se encuentre corriendo, reinciarlo).
$ npm start
> [email protected] start /development/noticias-unq
> babel-node -- index.js
Server running on port 3001
Para invocar las rutas deberemos utilizar algún cliente REST. A fines prácticos vamos a utilizar curl desde la linea de comando pero un cliente gráfico es a veces mucho más util al desarrollar. Recomendamos Postman para esto.
Primero creamos una nueva noticia:
$ curl -X POST \
-H 'Content-Type: application/json' \
-d '{ "title": "Noticia 1", "content": "lorem ipsum dolor sic" }' \
localhost:3001/noticias
OK
Luego recuperamos la lista de noticias:
$ curl -X GET localhost:3001/noticias
[{"title":"Noticia 1","content":"lorem ipsum dolor sic"}]