Hemos creado una aplicación de ejemplo para poder comprender mejor cómo podemos utilizar la librería jsRPC para gestionar de forma muy sencilla las llamadas a procedimientos remotos de forma transparente. En esta aplicación hemos utilizado el modelo RPC para que el navegador invoque funciones del servidor y para que los diferentes microservicios invoquen de forma remota funciones entre ellos.
El código fuente completo de este ejemplo lo puedes obtener en:
https://github.com/todojs/jsrpc-example
Es un proyecto con un cliente HTML + JS Vanilla (se puede usar cualquier framework front como React, Angular o Vue, pero hemos querido no distraer de la implementación) y un servidor en NodeJS con NeDB como sustituto a la base de datos (se podría haber usado MongoDB o una base de datos SQL).
Core
En primer lugar, hemos creado tres objetos: courses
, teachers
y students
. Como es fácil adivinar, es una micro aplicación de ejemplo para la gestión de cursos. Cada uno de estos objetos tiene los siguientes de métodos que realizan las operaciones que necesitamos en nuestra aplicación:
.list([query][, sort])
obtiene todos los registros en base a una query (por defecto devuelve todos) y un criterio de ordenación (por defecto se ordena por nombre)..get(id)
obtiene los datos detallados de un registro..add(data)
crea un nuevo registro..edit(id, data)
actualiza los valores de un registro..del(id)
elimina un registro.
Todos estos métodos devuelven una promesa. Si tenéis curiosidad por cómo están implementados en detalle estos métodos, podéis ver su código fuente en:
microservicios/courses/coures.js microservicios/teachers/teachers.js microservicios/students/students.js
Estos servicios se han probado con una serie de tests que también están incluidos en el repo y que por medio de Mocha y Chai van llamando a cada uno de los métodos comprobando diferentes combinaciones y casos.
Sub y Skeleton
La idea es que estos métodos se utilicen como llamadas locales (dentro del mismo espacio de direcciones, es decir, dentro del mismo programa) o como llamadas remotas (RPC) sin que tengamos que cambiar nada. Es decir, que si quiero obtener una lista con todos los alumnos (tanto remotamente como localmente) sólo tendré que llamar a:
students.list().then(function(data) { // … });
Para ello vamos a hacer uso de las funciones de jsRPC para crear el programa stub que utilizaremos en el cliente y el programa skeleton que usaremos en el servidor. Antes de esto tenemos que instalar la librería con:
npm install @todojs/jsrpc –save
En nuestro repo, al tenerlo ya incluido en las dependencias, basta con:
npm install
Para cada uno de los objetos se ha creado su programa squeleton, que se ejecutará en la parte remota, con la función skeletonify()
de la siguiente forma:
const courses = require ('./courses'); const skeletonify = require ('@todojs/jsrpc/skeletonify'); module.exports = skeletonify ('courses', courses);
De igual forma, para cada uno de los objetos se ha creado su programa stub, que se ejecutará en la parte local, con la función stubify()
de la siguiente forma:
(root => { const stubify = typeof window !== 'undefined' ? window.stubify : require ('@todojs/jsrpc/stubify'); const courses = stubify ("http://localhost:9001", 'courses'); if (typeof module !== 'undefined' && module.exports) { module.exports = courses } else { root.courses = courses; } }) (this);
El código de los stub está preparado para ser utilizado desde un navegador y desde un programa Node de forma indistinta, de esta forma podremos llamar remotamente a estas funciones desde cualquier sitio que las necesitemos.
Estructura de ficheros
Cada objeto de nuestra aplicación tiene ahora tres ficheros, uno con su código: courses.js
, otro con su programa skeleton: courses-squeleton.js
y otro con su programa stub: coures-stub.js
, y podemos distribuirlos según nuestras necesidades.
En muchas ocasiones el fichero con el stub tiene el mismo nombre que el fichero con los métodos originales, lo cual simplifica la sustitución de uno por otro, ya que no cambian el nombre del módulo. En nuestro caso los hemos dejado con nombres diferentes sólo con fines didácticos.
Desde el navegador vamos a querer llamar de forma remota a los tres objetos courses
, teachers
y students
, por lo que hemos incluido sus stub dentro de la carpeta front
, que incluye todo lo que vamos a servir al cliente. Como estos programas hacen uso de stubify()
también hemos movido aquí esta función desde la carpeta node_modules
, aunque también podríamos haber hecho una referencia para evitar realizar esta copia del fichero.
En el servidor hemos organizado la ejecución en tres microservicios, uno por cada uno de los objetos. Para simplificar el funcionamiento lo hemos preparado para que cada uno arranque en un puerto diferente:
courses
: puerto 9001teachers
: puerto 9002teachers
: puerto 9003
Cómo los métodos del objeto courses
llaman a su vez a métodos de los objetos teachers
y students
, y como estos se van a ejecutar en otro microservicio, hemos incluido los stub de estos objetos dentro de la carpeta del microservicio courses
. Cada uno de los microservicios tiene su propia carpeta con los datos que maneja, no accediendo directamente nunca unos a los datos de los otros.
En cada microservicio también hay un fichero index.js
que simplemente configura el puerto y llama al programa skeleton de cada uno de ellos:
process.env.port = process.env.port || 9001; require ('./courses-skeleton');
Ejecutar el ejemplo
Ya lo tenemos todo preparado, por lo que podemos empezar a arrancar cada uno de nuestros microservicios con:
cd microservices/courses node index.js
cd microservices/teachers node index.js
cd microservices/students node index.js
Ahora arrancamos el servidor http para que nos sirva la página de ejemplo:
./node_modules/.bin/http-server ./front -o
Si todo ha funcionado correctamente, se abrirá un navegador y podremos ir consultando las diferentes pantallas:
Llamadas entre los elementos
Para comprender un poco mejor cómo funciona, vamos a analizar cómo consultamos un detalle de un curso en el navegador. Para obtener todos los cursos se está haciendo una llamada de este tipo:
courses.get (id) .then (function (result) { //... }) .catch (function (err) { error (err.message); });
Este método courses.get()
se ejecuta en el servidor a través del sistema jsRPC, y este a su vez llama a métodos de students
y de teachers
:
const currrentTeachers = await teachers.list ({_id : {$in : data.teachers}}); // ... const currrentStudents = await students.list ({_id : {$in : data.students}});
Tal y como lo hemos configurado, estas llamadas son enviadas a los microservicios correspondientes que ejecutan remotamente las funciones que les hemos solicitado.
Ejecutar estos métodos local o remotamente sólo cambia si estamos invocando al módulo directamente o a su sustituto el stub, que es quien ser encarga de gestionar la llamada remota, por lo que nuestro código no se ve afectado por este cambio.
Conclusión
De esta forma podemos gestionar todas las comunicaciones entre las diferentes piezas de nuestro sistema de forma absolutamente transparente. Esta es la gran ventaja de las soluciones RPC, que nos permiten centrarnos en la funcionalidad de nuestro código y gestionan por nosotros todas las características internas de la comunicación entre los diferentes procesos.
Os invitamos a explorar este ejemplo y descrubir por vosotros mismos las capacidades que tiene el sistema jsRPC en concreto y las soluciones RPC en general.
Novedades
HTTP2 para programadores. Enviar mensajes del servidor al cliente con Server Sent Event (sin WebSockets)
En esta charla, organizada por MadridJS, Pablo Almunia nos muestra cómo la mayoría de nosotros cuando oímos hablar por primera vez de HTTP2 nos ilusionamos con las posibilidades que presumiblemente se abrían para el desarrollo de soluciones web avanzadas y cómo muchos nos sentimos defraudados con lo que realmente se podía implementar.
En esta charla podemos ver cómo funciona el HTTP2, que debemos tener en cuenta en el servidor para hace uso de este protocolo y, sobre todo, cómo podemos enviar información desde el servidor al cliente de forma efectiva y fácil. Veremos con detenimiento cómo por medio de los Server-Sent Events (SSE) podemos recibir en el cliente datos enviados desde el servidor sin utilizar websocket, simplificando enormemente la construcción de aplicaciones con comunicación bidireccional.
Observables en Javascript con Proxies
En esta charla, organizada por MadridJS, Pablo Almunia nos habla de la observación reactiva de objetos en Javascript por medio de Proxy. Se describe paso a paso cómo funcionan los Proxies y en que casos pueden ser nuestro mejor aliado. Veremos que no hay que tenerles miedo, son bastante sencillos de utilizar, y nos ofrecen una gran abanico de posibilidades.
Aplicaciones JAMStack, SEO friendly y escalables con NextJS
En esta charla de Madrid JS, Rafael Ventura nos describe las funcionalidades clave de NextJS, nos muestra en vivo cómo desarrollar una completa aplicación JAMStack con Server Side Rendering (SSR) y Static Site Generation (SSG) y termina mostrando como publicar esta aplicación en Vercel.
Stencil JS: mejora el Time To Market de tu producto, por Rubén Aguilera
En esta charla Rubén Aguilera nos cuenta los problemas que tienen muchas empresas a la hora de sacar productos accesibles, vistosos y usables en el Time To Market que requiere Negocio y cómo podemos minimizar este tiempo gracias al DevUI con StencilJS para adecuar una aplicación de Angular a las exigencias del mercado en tiempo record.