Seleccionar página
Como comentamos en un artículo anterior, los sistemas RPC son extremadamente flexibles y permiten llamar a funciones remotas de forma prácticamente transparente, pudiendo centrar nuestros esfuerzos de desarrollo en la funcionalidad y no en los mecanismos de comunicación entre las distintas partes de nuestra aplicación.

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 9001
  • teachers: puerto 9002
  • teachers: 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

Datos inmutables en Javascript

Datos inmutables en Javascript

En Javascript todo parece mutable, es decir, que se puede cambiar, pero lo cierto es que también nos ofrece varios mecanismos para conseguir que los datos que manejamos, especialmente los objetos, sean inmutables. Te invitamos a descubrir cómo…

Copiar objetos en Javascript

Copiar objetos en Javascript

Copiar objetos no es algo sencillo, incluso se podría decir que en si mismo no es posible, ya que el concepto «copiar» no entra dentro del paradigma de los objetos. No obstante, por medio de instrucciones como Object.assign() hemos aprendido como obtener objetos con las mismas propiedades, pero está técnica no se puede aplicar a todos los tipos de objetos disponibles en Javascript. Vamos a ver cómo podemos copiar cualquier tipo de objeto…

Descubre los Javascript Array Internals

Descubre los Javascript Array Internals

El Array es una de las estructuras más utilizadas en Javascript y no siempre bien comprendida. Hoy os invitamos a analizar el comportamiento interno de este objeto y descubrir cómo Javascript implementa las diferente acciones con los Array y que operaciones internas se realizan en cada caso.

Web Components: pasado, presente y futuro

Web Components: pasado, presente y futuro

Los Web Components aparecieron en el panorama de desarrollo hace ya bastante tiempo. Desde su presentación se les ha prestado mucha atención, pero lo cierto es que no han sido acogidos de forma generalizada, quizás por la difusión de nuevos y potentes frameworks. Nos preguntamos qué ha pasado con este estándar y, sobre todo, que puede pasar de aquí en adelante con el uso práctico de los componentes web.