Introducción a gRPC y Node.js: Un Enfoque Moderno en Comunicación entre Servicios

Darwingrisalesg
Pragma
5 min readFeb 5, 2024

--

En el mundo actual de la programación, donde las aplicaciones se vuelven cada vez más complejas y distribuidas, la eficiencia en la comunicación entre servicios es esencial. Aquí es donde entra en juego gRPC, un sistema de código abierto desarrollado por Google que facilita la creación de servicios eficientes y rápidos a través de la comunicación remota de procedimientos (RPC). Este artículo explorará cómo implementar gRPC en Node.js, destacando sus ventajas y proporcionando ejemplos prácticos.

¿Qué es gRPC?

gRPC, que significa “Google Remote Procedure Calls”, es un marco de trabajo de comunicación entre servicios que utiliza el protocolo HTTP/2 para el transporte y Protocol Buffers como su formato de interfaz. Es conocido por ser eficiente, interoperable y fácilmente extensible.

Configuración del Entorno:

Antes de comenzar, asegúrate de tener Node.js instalado en tu sistema. Luego, puedes instalar las dependencias necesarias.

Inicia el proyecto en NodeJs ejecutando el siguiente comando

npm init -y

Instala las dependencias necesarias para utilizar grpc con el siguiente comando:

npm install @grpc/grpc-js @grpc/proto-loader

Seguido de esto, podemos crear un script bash en la raíz de nuestro directorio para ejecutar la compilación de nuestros protocol buffers. En este caso, lo llamaré gen.bash:

#!/bin/bash

npx proto-loader-gen-types --longs=String --enums=String --defaults --oneofs --grpcLib=@grpc/grpc-js --outDir=proto/ proto/*.proto

Puedes crear un script en el package.json para ejecutarlo de forma más sencilla de la siguiente manera:

"scripts": {
"compile": "chmod +x gen.bash && ./gen.bash"
}

El comando compile hará lo siguiente:

  • "compile": Este es el nombre del script. Puedes ejecutar este script usando el comando npm run compile en la terminal.

"chmod +x gen.bash && ./gen.bash": Este es el comando real que se ejecuta cuando ejecutas el script "compile". Desglosemos las partes:

  • chmod +x gen.bash: chmod es un comando de Unix/Linux que se utiliza para cambiar los permisos de un archivo. En este caso, +x está agregando el permiso de ejecución al archivo "gen.bash". Esto significa que el archivo ahora puede ser ejecutado como un programa.
  • &&: Este es un operador lógico que significa "y". En este contexto, se asegura de que la segunda parte del comando solo se ejecute si la primera parte (cambiar los permisos) se realiza con éxito.
  • ./gen.bash: Esto ejecuta el archivo "gen.bash" después de haberle otorgado el permiso de ejecución. El ./ indica que el archivo está en el directorio actual.

Creación de un Servicio gRPC:

1. Definición del Servicio:

Primero, define tu servicio y sus métodos utilizando Protocol Buffers en un archivo `.proto`. Por ejemplo, crea un archivo en una carpeta llamada proto y dentro colocamos nuestro archivo llamado`books.proto` con el siguiente código:

syntax="proto3";

package books;

service MY_BOOK_SERVICES {
rpc getAllBooks(BOOK_REQUEST) returns (BOOK_RESPONSE) {}
}

message BOOK_REQUEST {
string title = 1;
}

message BOOK {
string title = 1;
}

message BOOK_RESPONSE {
repeated BOOK data = 1;
}

En este caso estamos definiendo nuestro servicio por medio de la palabra clave service, en el cual definimos los métodos que tendra nuestro backend, generando un contrato bien estructurado

por otro lado, nuestros modelos son definidos con la palabra clave message, donde definimos las propiedades que tendran nuestros servicios en los parametros de entrada y salida.

Recuerda ejecutar npm run compile cada vez que hagas una modificación a los archivos .proto.

2. Implementación del Servicio en Node.js:

Luego, implementa el servicio en Node.js utilizando gRPC. Crea un archivo `server.js`:

const path = require('path');
const grpc = require('@grpc/grpc-js');
const protoLoader = require('@grpc/proto-loader');

const PROTO_PATH = path.join(__dirname, './proto/books.proto');

const packageDefinition = protoLoader.loadSync(PROTO_PATH, {
keepCase: true,
longs: String,
enums: String,
defaults: true,
oneofs: true,
})

const protoService = grpc.loadPackageDefinition(packageDefinition).books;

const server = new grpc.Server();

server.addService(protoService.MY_BOOK_SERVICES.service, {
getAllBooks: (call, callback) => {
const books = [{ title: 'Libro 1'}, { title: 'Libro 2'}];
const data = books.filter((book) => book.title === call.request.title)
callback(null, { data });
}
})

server.bindAsync('0.0.0.0:50051', grpc.ServerCredentials.createInsecure(), () => {
server.start();
console.log('Servidor gRPC iniciado en el puerto 50051');
})

En este ejemplo estamos utilizando la librería de node llamada path para obtener la ruta de nuestro archivo .proto, el cual nos permitirá cargar nuestros contratos con la librería @grpc/proto-loader.

Continuamos con la creación de nuestro servidor y agregamos nuestros servicios que se cargaron anteriormente en la variable protoService, aqui agregamos toda nuestra lógica.

finalmente, creamos una instancia de nuestro servidor, en este caso usamos createInsecure para temas de pruebas locales, pero en producción puedes crear un servidor ssh para mayor seguridad.

3. Consumo del Servicio gRPC:

Ahora, puedes consumir este servicio desde otro servicio o cliente Node.js. Crea un archivo `client.js`:

const path = require('path');
const grpc = require('@grpc/grpc-js');
const protoLoader = require('@grpc/proto-loader');

const PROTO_PATH = path.join(__dirname, './proto/books.proto');

const packageDefinition = protoLoader.loadSync(PROTO_PATH, {
keepCase: true,
longs: String,
enums: String,
defaults: true,
oneofs: true,
})

const protoService = grpc.loadPackageDefinition(packageDefinition);

const client = new protoService.books.MY_BOOK_SERVICES('localhost:50051', grpc.credentials.createInsecure());

const request = { title: 'Libro 1'};

client.getAllBooks(request, (error, response) => {
if (error) {
console.error('Error al llamar al servidor:', error);
return
}
console.log('Respuesta del servidor', response)
})

En este ejemplo nuevamente utilizamos la librería de node llamada path para cargar nuestro archivo .proto en el lado del cliente de la comunicación grpc.

Continuamos creando una instancia de nuestro servicio, pasando la url del servidor y las credenciales, en este caso, se utiliza createInsecure para temas de pruebas pero igualmente puedes usar un servidor ssh para mayor seguridad.

Finalmente, llamamos los métodos que se definieron en el archivo .proto y pasamos los parametros necesarios para obtener una ejecución de nuestro programa con grpc.

4. Resultado de ejecución:

Ejecutamos node server.js para iniciar nuestro servidor. Este estará escuchando las peticiones de las aplicaciones con el cliente gRPC. Tendremos esto en la consola:

resultado de server.js: Servidor gRPC iniciado en el puerto 50051

Para realizar una petición desde nuestro cliente, podemos ejecutar node client.js y obtendremos el siguiente resultado en la consola:

resultado de client.js: Respuesta del servidor { data: [ { title: ‘Libro 1’ } ] }

Como podemos ver, nuestro servidor está dando una respuesta exitosa a nuestro cliente gRPC. Con esto, podemos establecer una comunicación óptima entre nuestros microservicios.

Ventajas de gRPC con Node.js:

1. Eficiencia en la Comunicación:

gRPC utiliza HTTP/2, permitiendo la multiplexación de múltiples llamadas en un solo canal. Esto mejora significativamente la eficiencia en la comunicación entre servicios.

2. Interoperabilidad:

gRPC es compatible con varios lenguajes de programación, lo que facilita la construcción de sistemas distribuidos heterogéneos.

3. Protocol Buffers:

El uso de Protocol Buffers para definir la interfaz del servicio resulta en una serialización eficiente y un contrato claro entre los servicios.

Conclusión:

Implementar gRPC en Node.js proporciona una solución eficiente y moderna para la comunicación entre servicios. Con su enfoque en la eficiencia, interoperabilidad y facilidad de uso, gRPC se destaca como una opción sólida en el desarrollo de sistemas distribuidos. Conviértete en un maestro de gRPC y lleva tus aplicaciones a un nuevo nivel de rendimiento y escalabilidad.

--

--