La herramienta de Node.js para la creación de APIs REST

por Gerardo Fanjul

Objetivo

Vamos a desarrollar una pequeña API RESTfull con Node.js. El proyecto quedará adjunto node-rest-shop.zip.

Introducción

Node.js es un entorno de ejecución para JavaScript construido con el motor de JavaScript V8 de Chrome. Trabaja en tiempo de ejecución, de código abierto, multi-plataforma, que permite a los desarrolladores crear toda clase de herramientas de lado servidor y aplicaciones en JavaScript. La ejecución en tiempo real está pensada para usarse fuera del contexto de un explorador web (es decir, ejecutarse directamente en una computadora o sistema operativo de servidor). Node.js cambia el paradigma de JavaScript, donde el código se alojaba del lado del cliente y solo el web server lo ejecutaba.

Tecnologías

Para la explicación de como crear una pequeña aplicación REST vamos a utilizar las siguientes herramientas/tecnologías:

  •  NPM es el gestor de paquetes de Node.js (NPM del inglés: Node Packet Manager) proporciona acceso a cientos o miles de paquetes reutilizables. Además la resolución de dependencias es la mejor en su clase y puede usarse para automatizar herramientas de compilación.
  • Express.js es el framework web más popular de Node.js, y es la librería subyacente para un gran número de otros frameworks web de Node.js.
  • MongoDB es una base de datos no relacional con la escalabilidad y flexibilidad deseable en consultas e indexación. Además almacena datos en documentos flexibles, similares a JSON, los campos pueden variar de un documento a otro así como la estructura misma. La colección en MongoDB se correlaciona con los objetos en el código de la aplicación, facilitando el trabajo de los datos.
  • Mongoose es un framework para trabajar con MongoDB.
  • Morgan es un paquete de logging para Node.js.
  • Jest es un framework de testing lanzado por primera vez en 2014, y aunque inicialmente despertó un gran interés, el proyecto estuvo inactivo durante un tiempo. Sin embargo, Facebook intervino en el 2016 para mejorar Jest, y publicó algunos lanzamientos con cambios impresionantes que hacen que valga la pena reconsiderar. La única semejanza de Jest en comparación con la versión de código abierto inicial es el nombre y el logotipo. Todo lo demás ha sido cambiado y reescrito.

Supertest es una librería para testing unitario de node.js.

Agregados técnicos

Características de NPM
1) El documento donde está toda la información requerida acerca de los paquetes requeridos en la aplicación es package.json. Debe estar en formato JSON, no solo JavaScripts.
2) Si la aplicación va a ser publicada, se debe agregar un nombre y versión en este archivo, por ejemplo:

package.json

Express tiene las siguientes características y/o funcionalidades.

  • Escritura de manejadores de peticiones con diferentes verbos HTTP en diferentes caminos URL (rutas).
  • Integración con motores de renderización de “vistas” para generar respuestas mediante la introducción de datos en plantillas.
  • Establecer ajustes de aplicaciones web como qué puerto usar para conectar, y la localización de las plantillas que se utilizan para renderizar la respuesta.
  • El servidor propone un principio basado en eventos, el cual es elemento central del funcionamiento interno entre Express y NodeJS. Se caracteriza por la falta de bloqueo de datos durante el procesamiento de cualquier solicitud recibida. Y se logra mediante el procesamiento paralelo de datos para evitar retrasar el flujo de los mismos. Por lo tanto, NodeJS puede procesar un mayor número de solicitudes de una manera más eficiente.

Creando una API RESTFull

El desarrollo contendrá un módulo javascript llamado server.js en el cual se configura la publicación de la api (sobre node.js) como ser puerto y protocolo (por ejemplo https).

Este será el encargado del despliegue de la app.js la cual recepcionará los pedidos y delegará a quien (router) va a encargarse de tal pedido, además de encargarse de los errores de pedidos no soportados o errores de servidor internos.

Al llegar el pedido hacia alguno de los routers (en nuestro caso products.js) y dependiendo del método invocado, se accederá a la implementación del mismo. Y el cual requerirá de un modelo del esquema en la base de datos para la manipulación de los datos (product.js).

Para crear un proyecto con Node.js ejecutamos el comando npm init, nos pedirá información acerca de nuestra api como el nombre y versión. Este comando nos creará el archivo necesario (package.json) para la ejecución de la app en Node.js.

Luego comenzamos a instalar los frameworks que utilizaremos npm install –save express, el cual nos agregará las librerías de dicho framework a nuestro proyecto.

Yendo directamente a la implementación creamos una API RESTFull y aceptar peticiones /products. En un primer momento solo aceptaremos pedidos get y post sin utilizar base de datos y luego se irá incrementando el código para el uso de datos.

La estructura del proyecto lucirá de la siguiente manera:

Para la recepción de pedidos desarrollamos un módulo app.js el cual utilizará el framework Express.js para delegar el routeo de los pedidos. En este caso recepcionará ‘/products’ además de encargarse de manejar dos tipos de errores: pedidos no soportados e internos.

app.js

Para que esta API quede utilizable y publicada en un servidor necesitamos de un nuevo módulo llamado server.js en el cual se configura puerto y protocolo en donde se desplegará nuestra app.js.

server.js

Luego que los pedidos son recepcionados por la app.js, estos son redirigidos al router que atenderá los mismos.

Para atender dichos pedidos creamos un router (products.js) el cual va a ser aceptado por el servidor. En este ejemplo solo aceptará peticiones por métodos GET y POST http y retronará un objeto json con un mensaje.

products.js

Se puede observar que captura peticiones ‘/’ ya que nuestra API ya procesa los pedidos ‘/products’.

Utilizando MongoDB

En nuestra aplicación solo se requiere la utilización del framework mongoose y luego conectar con nuestro esquema.

mongodb

Objetos

Como primer paso debemos crear nuestro módulo de asociación entre nuestro código y una colección de datos en nuestro esquema de MongoDB.

product.js

Manipulación de los objetos

Tan solo importando el framework y el módulo creado anteriormente ya estamos habilitados a manipular esta colección en nuestro esquema.

Para ello modificamos el código del router products.js para obtener datos de nuestro esquema. Aquí utilizaremos funciones provistas por mongoose como ‘find’ para buscar datos, ‘select’ para seleccionar los datos que queremos proyectar en nuestra consulta (en este caso solo nombre, precio y id).

Luego ejecutamos la consulta con la función ‘exec’ y para manipular los datos sincrónicamente concatenamos la función ‘then’.

products.js

Testing unitario

En esta API sencilla solo creamos un test del router de productos. Para ello vamos a instalar el framework jest junto con supertest.

products_router.test.js

Configuración y ejecución

Para configurar la ejecución del test desde línea de comandos mediante npm test, es necesario modificar una línea en el archivo package.json.

package.json

Y como resultado del test obtenemos una interfaz como la siguiente:

Para desarrollar test más completos, asincrónicos con esperas, sin utilizar supertest ver referencia [8].

Otros aperitivos

Cambios en tiempo de ejecución
Algo muy esperable en entornos como Node.js es que al momento de modificar código en el desarrollo no sea necesario parar la ejecución del servidor y volver a ejecutarlo.

Para esto existe un paquete llamado nodemon el cual monitorea nuestro proyecto Node.js y nos reinicia el servidor cuando hay un cambio en los archivos del mismo.

Lo podemos instalar con npm install –save-dev nodemon y luego agregarlo en el archivo de package.json bajo el item scripts:

package.json

Ahora para correr el servidor basta con npm start y quedará levantado el servidor que ante cambios en el código se reiniciará automáticamente.

Logging con Morgan

Para loggear en nuestra aplicación Node.js vamos a utilizar Morgan.

Lo podemos instalar con npm install –save-dev morgan. Y para utlizarlo desde la app solo se necesita requerir el paquete.

package.json

Para probarlo basta con realizar un request a ‘/products’ y podemos ver un ejemplo de dicho pedido.

En esta prueba observamos en la consola el loggeo de nuestras peticiones y la obtención de datos de la base de datos.

logging

Buenas prácticas

  1. Organiza los archivos por features, no por roles (por ejemplo: productos, ordenes, etc y no por routers, models, etc).
  2. No agregues lógica en archivos index.js (para aplicaciones web).
  3. Coloca los test cerca de la implementación.
  4. Utiliza un directorio para la configuración (en este proyecto no se utilizó).
  5. Coloca tus scripts npm en un directorio de scripts.
  6. Nomenclatura: routers en plural, modelo en singular y el test ‘modulo.test.js’

Comentarios

  1. En mi opinión Node.js es una potente y rápida herramienta para la creación de APIs.
  2. Es fácil de implementar ya que solo lleva unos minutos publicar una API (comparándolo con una aplicación java con spring boot), desarrollar tests unitarios y su despliegue en servidores de producción.
  3. Por otro lado la curva de aprendizaje para llegar a un nivel de ‘expertice’ necesario para desarrollar un proyecto de mediano porte es alta. Ya que se utilizan frameworks y/o librerías totalmente nuevos en lo que confiere al desarrollo de software.

Referencias

[1] Node.js, https://nodejs.org/es/

[2] MongoDB, https://www.mongodb.com/

[3] Mongoose, http://mongoosejs.com/

[4] Express web framework, https://developer.mozilla.org/es/docs/Learn/Server-side/Express_Nodejs

[5] Express Pros y Cont, http://www.binariks.com/blog/tools/express-js-mobile-app-development-pros-cons-developers/

[6] Estructura del proyecto, https://blog.risingstack.com/node-hero-node-js-project-structure-tutorial/

[7] Jest.js, https://jestjs.io/

[8] Supertest, http://www.albertgao.xyz/2017/05/24/how-to-test-expressjs-with-jest-and-supertest/