API REST Básica con Express.js — Parte II

thaisDev
12 min readSep 14, 2019

--

Parte I

En este post te enseñaré a crear una API REST usando a Express como servidor y a un archivo JSON como base de datos, mencionar que, solo nos enfocaremos en construir el Backend.

Herramientas :

Visual Studio Code — Editor de Código donde escribiremos la magia.

Postman es un cliente HTTP que nos permitirá gestionar las peticiones a nuestras API, imagínatelo como si fuera chrome,firefox,opera, cualquier navegador puesto que con él testearemos las rutas de nuestra API.

Vamos a empezar creando la estructura del proyecto, el estado inicial sería este :

app.js — Donde tendremos todas las rutas y configuraciones de Express, no es lo ideal en absoluto pero de momento nos servirá para aprender.

movies.json — Donde guardaremos nuestras pelis, será como nuestra base de datos pero a lo chano.

Ahora vamos a traernos 2 colegas llamados módulos ( Un módulo es una librería o archivo JavaScript con una o varias funcionalidades que podemos utilizar para nuestro beneficio añadiéndolo a nuestro proyecto, a esta tarea se le llama importar y para ello empleamos la función require() de Node), te presento al que será nuestro Lord comandante y servidor de operaciones, el aclamado y venerado, Express.js

Y al que será nuestro encargado de revisar y estar atento en todo momento a los cambios efectuados en el código para aplicarlos y que veamos siempre un estado actualizado de lo que hagamos, nuestro compañero con nombre de Digimon, NODEMON!!!

Vamos a la faena, necesitaremos a npm (gestor de dependencias de node)para traernos a estos 2 titanes, empezaremos creando un fichero llamado package.json la existencia de este fichero se resumen en

  • Proporcionar una descripción del proyecto así como las dependencias necesarias para que funcione. Esto quiere decir que si un día te dan un proyecto para que participes en él simplemente ejecutando en la terminal el comando npm install se te descargarán todas las dependencias necesarias y así no tienes que estar uno a uno mirando qué modulos te hacen falta, porque npm install lee el package.json y te ahorra esa jodienda.

Para crear un package.json rula el comando :

Creamos el package.json

Con el flag -y le dices a npm que quieres que te cree el package.json pero sin preguntar nada a que a todo le dices que sí y se calle. Si no pusieras el flag -y, npm te haría un interrogatorio sobre el proyecto que quieres crear, recomendable hacerlo sin el flag si quieres subir una librería o compartirlo con el mundo, así todo el mundo sabrá de qué va y qué hace lo que has creado.

Deberías obtener este resultado :

Resultado de ejecutar el comando npm init -y

fs : Node.js File System Module

Lo necesitaremos cuando vayamos a leer el fichero movies.json, cuando llegue el momento hablaremos de él.

Ahora instalaremos los 2 módulos que de momento necesitamos :

  • i se refiere a install con esto estamos diciendo, “hey npm, instala express de manera local por favor”
Instalar express.js
  • puedes instalar varios módulo juntos así : npm i express nodemon, pero a mi me gusta dejar a nodemon como una dependencia de desarrollo, ¿qué quiere decir esto?, que no será vital para que el proyecto funcione pero nos ayudará mientras desarrollamos.
  • - g : significa que lo quiero instalar globalmente, así evito que me escupa “nodemon command not found”, a la hora de arrancar el servidor porque lo reconocerá a nivel de sistema operativo.

Si quieres instalar nodemon como una dependencia de desarrollo añade el flag que se muestra en la imagen ó -D.

  • -D : significa que lo quiero instalar como una dependencia de desarrollo.

Las dependencias de desarrollo (-D) se ven así en el package.json :

A estas alturas deberás tener algo como esto :

  • node_modules : Es una carpeta donde reside ̶e̶l̶ ̶s̶e̶c̶r̶e̶t̶o̶ ̶d̶e̶ ̶l̶a̶ ̶v̶i̶d̶a̶, los módulos, cuando haces un const miVuesito = require(‘vue’), estás especificando que ese módulo que requieres vaya Javascritpt a buscarlo a la carpeta node_modules.
  • package-lock.json: El hermano gemelo malvado de package.json es un fichero donde y citando a vamoacodearlo.com :

La finalidad es que se pueda mantener un detalle específico de las versiones de dependencias que tienes instaladas en el proyecto. Esto sirve, por ejemplo, para garantizar que todos los que estamos trabajando en un proyecto tengamos instaladas las mismas versiones de paquetes y evitar tener problemas con distintas versiones de dependencias.

Para más información acerca del hermano gemelo malvado y aclarar la duda que tienes ahora mismo te invito a que pases por + info package-lock.json

Y en el package.json deberás tener algo como esto :

Montando Express para la Acción

Lo primero que debemos hacer es traernos a express, con esta línea estamos diciendo, “oye mira vete a buscarme a la carpeta node_modules el express este anda y ya de paso asignamelo a la constante express, graciaaas”

Pero como express por sí solo es un chorro de cosas, tiene un maravilloso método para dejarnos de tanta parafernalia e inicializar el servidor cuanto antes.

Y para que esta explicación quede más pro, invoco a MDN Web Docs Mozilla y su definición al respecto :

Las primeras dos líneas incluyen (mediante la orden require()) el módulo de Express y crean una aplicación de Express. Este elemento se denomina comúnmente app, y posee métodos para el enrutamiento de las peticiones HTTP, configuración del middleware ,y visualización de las vistas de HTML, uso del motores de 'templates', y gestión de las configuraciones de las aplicaciones que controlan la aplicación (por ejemplo el entorno, las definiciones para enrutado ... etcetera.)

Te dejo el enlace por si deseas saber más información aquí.

Con app.use(express.json()) le decimos a Express que convierta a formato JSON los datos que recibimos de la petición de cliente (me refiero al request.body que vendría a ser la información que nos envía el cliente o como me gusta llamarlo, “ el cuerpazo de la petición”).

El siguiente código, define y crea el servidor, escuchando en el puerto 3000 e imprime el comentario “Estoy escuchando por el puerto 3000” en la consola.

Vistazo completo con terminal incluida :

Sip, mi ordenador se llama Ferchillo

Antes de juguetear con Postman, quiero que abras una pestaña en tu navegador y en la barra de direcciones pongas localhost:3000

¿Te aparece esto?, pues bien saroto, en fin…¿sabes por qué el Chrome nos está escupiendo semejante cosa?, ¿recuerdas para qué se definió el método GET?, pues bien, Chrome nos está diciendo que no encuentra nada que hacer porque GET no está obteniendo nada de ningún sitio, por eso te escupe eso, no sabe qué mostrar.

Aaaah pero si ahora yo le digo que muestre “Hola Chrome, qué tal?”, cuando vea que se está accediendo a la ruta ‘/’ mediante el método GET, ¿qué pasará?

En efecto, ahora Chrome sabe qué hacer cuando se manda al servidor una petición GET y es la de mostrar ese mensaje, siguiendo esta instrucción response.send('Hola Chrome,¿qué tal?👋'). el servidor le manda al cliente una respuesta y corta la comunicación, esto quiere decir que si pones 2 response.send(); uno debajo del otro únicamente el cliente verá el primero y en la consola te aparecerá el Error : Cannot set headers after they are sent to the client.

Vamos a definir los endpoints de nuestro proyecto para tener una visión general de cómo se va a navegar a través de las distintas rutas :

GET → /movies

POST → /movies

PATCH → /movie/id

DELETE → /movie/id

Obtener todas las películas de movies.json — GET

Ha llegado el debut de Postman y a partir de ahora todas las peticiones que hagamos las veremos con él. Como el archivo movies.json estaba un poco sosete he añadido 2 películas que son :

Para leer el contenido del fichero debemos emplear el módulo File System de node o para los amigos fs.

No te abrumes con tanto código, vamos a seguirlo :

  1. const fs = require('fs'), le digo a Node que quiero su tremendo módulo de sistemas de ficheros para poder leer después el fichero de las pelis
  2. app.get('/movies',(req,res)=>{digo que en el endpoint (/movies) va a tener que hacer una serie de cositas:
  • Con el módulo fs quiero que leas asíncronamente el contenido del fichero movies.json, tómate todo el tiempo que quieras pero si cuando vengas me dices que hay un errorcito, en la consola imprime ese mensaje y el errorcito en cuestión
  • Si todo sale a pedir de milhouse y me entregas el contenido del fichero quiero que esa breva me la conviertas a un objeto de Javascript const movies = JSON.parse(file) para poder manipular los datos.
  • Finalmente responde al cliente dándole las pelis que ha pedido en formato JSON con return res.json(movies);(req es request y res es response).

Si nos vamos a Postman y le damos al send aparece la magia :

Crear una peli — POST

Ahora queremos añadir una película a nuestro archivo movies.json y para crear un nuevo recurso empleamos al señor POST.

En Postman hay muchos caminos para escribir la petición, personalmente me gustan estas 2:

  • Raw (a pelo) e indicándole JSON(application/json) como en la imagen
  • Formulario (x-www-form-urlencoded) e indicándole JSON(application/json) (este lo veremos más tarde)

Bien,nuestro código Javascript deberá ser capaz de interceptar la petición y guardarla en movies.json :

¿Por qué no añades el ID en la petición?, porque esta tarea es preferible delegarsela al servidor aunque la forma en la que le digo que calcule el ID no es la más ideal pero sí es la más comprensible a nivel educativo.

Y … ¿Cómo calculo ese ID? pues la tarea del servidor consistirá en leer el fichero para recoger la longitud del array de objetos y usar ese número como id para identificar futuras películas que se añadan, es por ello que, incremento en 1 esa longitud y ya obtendría el nuevo ID.

const newMovieID = movies.length + 1 // el ID será 3 ya que tenemos 2 pelis en el array

req.body.id = newMovieID Añado el ID para que identifique la nueva peli

movies.push(req.body); Agrego la nueva peli a mi array de películas

Ahora le digo que quiero que ese mismo array de objetos Javascript lo convierta a formato JSON pero, que en vez de sacarme un churrasco como este :

Vamos a decirle que añada 2 espacios para que todos los humanos podamos leerlo de forma clara y mágica :

const newMovieArray = JSON.stringify(movies,null,2) // El array movies ahora tiene la nueva peli y está lista para ser agregada al fichero

Llegó el momento de agregar contenido a nuestro fichero y para ello empleamos el método writeFile que tiene fs :

writeFile nos solicita :

  • El fichero en el cual queremos escribir (movies.json)
  • El contenido a escribir (newMovie)
  • Callback(sacará un error si ocurriera)

Tened cuidado con writeFile ya que su comportamiento es el de borrar el contenido anterior y sustituirlo por el nuevo, es por ello que yo le estoy mandando todo el array de películas, porque si únicamente le mandaramos la película que queremos añadir nos borraría las películas anteriormente almacenadas y la jodimos fuerte. (Existe appendFile() para añadir contenido sin borrar el existente pero yo soy cabezota y uso writeFile porque oye ni tan mal si lo hago como en la imagen).

Finalmente con return res.status(200).send("new movied added") le indicamos que la operación ha sido un éxito (código 200 : 👌) y le enviamos al cliente la respuesta de que la peli ha sido añadida.

Ahora el Gif chachongo que te muestra en tiempo real el proceso :

Actualizar una peli — PATCH

Para actualizar los datos de una película lo haremos de la siguiente manera empleando al sujeto PATCH :

La víctima a la que vamos a rebautizar como “a chupi flower” responde al nombre de El Rey León por lo que procedemos a ejecutar tal honor :

Cuando queremos actualizar el dato de un registro ya almacenado, debemos indicar en el endpoint a quién vamos a realizarle cambios, El Rey León tiene el id = 3 es por ello que ponemos localhost:3000/movie/3.

Como en las anteriores operaciones GET & POST vamos a leer del fichero nuestras pelis pero esta vez detectando aquella que coincida con el id que nos han mandado en la petición :

if (movie.id == Number(mid))// mid es string por eso convierto a numero

Como explico en el Gist, cuando veamos en la petición que un campo contiene el valor “undefined” es que no ha sido modificado por tanto se conservará su valor que no se verá afectado en ningún momento.

Una vez, tengamos los cambios realizados decimos que los escriba en el fichero para que se queden almacenados y no se pierdan (persistencia de datos 🧐).

Por último le decimos que si todo ha salido perfect, nos mande un json con ese mensaje y además nos muestre la peli con los datos actualizados :

return res.status(200).json({message: “movie updated”, peliActualizada: movie});

Llegó el momentazo de verlo en acción :

DESTRUIR UNA PELI — DELETE

Siguiendo el mismo razonamiento para actualizar una peli vamos a DESTRUIR una peli 😊

El método splice() cambia el contenido de un array eliminando elementos existentes y/o agregando nuevos elementos. Por lo que lo emplearemos para DESTRUIR la peli seleccionada.

movies.splice(movies.indexOf(movie),1); // 🔫chop chop madafacka

Y como siempre para guardar los cambios escribiremos en el fichero su defunción

Procedemos a la exterminación de a chupi flower :

Y hasta aquí queridos amantes de la DESTRUCCIÓN y las API REST pero no me despido sin antes comentar que esta API REST está lejos, lejísimos de ser perfecta, ¿por qué?, bueno nos hemos saltado unas cuantas cosis como :

  • Validación — y si quiero eliminar una peli que no existe?, crear una que ya existe?, obtener únicamente una peli y ver sus cosis?.
  • Routing como los pros — Ahora mismo es adorable pero fea, feísima lo ideal sería tener la navegación en otro fichero aparte.

Y paro de agobiarte pero espero que con esto hayas podido comprender las API REST en su forma más básica, en futuros posibles post veremos cómo incorporar una Base de Datos (mongoDB) como dicta el manual y no en un fichero chano JSON.

yyyyyyyyy, ya por último de lo último te invito a ver los post de John Fredy Baquero que están tremendisimos porque te explica cómo crear un servidor web en Nodejs sin tonterías de librerías externas jeje.

Chauski y que pases buena mañana, tarde, noche 🤘

Bibliografía

--

--

thaisDev

Junior Developer #Laravel #Node #MySQL #React (react y yo estamos pasito a pasito) , me gusta compartir todo lo que aprendo!