gRPC para JavaScript (Node.js): bibliotecas y ejemplos
gRPC es un framework de alto rendimiento para llamadas a procedimientos remotos (RPC), desarrollado por Google. Utiliza Protocol Buffers (protobuf) para la serialización de datos y HTTP/2 para el transporte. En el ecosistema de Node.js, gRPC permite crear microservicios robustos con tipado estricto, soporte de streaming y comunicación bidireccional. En este artículo, revisaremos las bibliotecas principales para trabajar con gRPC en JavaScript (Node.js) y analizaremos un ejemplo práctico de servidor y cliente.
Bibliotecas principales para gRPC en Node.js
Para trabajar con gRPC en Node.js se utilizan dos paquetes principales:
- @grpc/grpc-js — una implementación pura de gRPC en JavaScript. No requiere dependencias nativas, funciona en todas las plataformas y soporta todas las funciones de gRPC (llamadas unarias, streaming del servidor y del cliente, streaming bidireccional).
- @grpc/proto-loader — una utilidad para cargar archivos
.protoen tiempo de ejecución. Permite crear dinámicamente objetos de JavaScript a partir de definiciones de Protobuf.
Para compilar archivos .proto en módulos estáticos, se puede usar grpc-tools (parte de grpc-tools), pero en proyectos modernos se prefiere la carga dinámica mediante @grpc/proto-loader.
Instalación de dependencias
npm install @grpc/grpc-js @grpc/proto-loaderEjemplo: definición del archivo Proto
Creemos un archivo helloworld.proto con un servicio simple:
syntax = "proto3";
package helloworld;
service Greeter { rpc SayHello (HelloRequest) returns (HelloReply) {}}
message HelloRequest { string name = 1;}
message HelloReply { string message = 1;}Parte del servidor (Node.js)
Creemos un archivo server.js:
const grpc = require('@grpc/grpc-js');const protoLoader = require('@grpc/proto-loader');const path = require('path');
const PROTO_PATH = path.join(__dirname, 'helloworld.proto');
const packageDefinition = protoLoader.loadSync(PROTO_PATH, { keepCase: true, longs: String, enums: String, defaults: true, oneofs: true});
const helloProto = grpc.loadPackageDefinition(packageDefinition).helloworld;
function sayHello(call, callback) { const name = call.request.name || 'Invitado'; callback(null, { message: `¡Hola, ${name}!` });}
function main() { const server = new grpc.Server(); server.addService(helloProto.Greeter.service, { sayHello: sayHello }); server.bindAsync('0.0.0.0:50051', grpc.ServerCredentials.createInsecure(), () => { console.log('Servidor gRPC iniciado en el puerto 50051'); server.start(); });}
main();Parte del cliente (Node.js)
Creemos un archivo client.js:
const grpc = require('@grpc/grpc-js');const protoLoader = require('@grpc/proto-loader');const path = require('path');
const PROTO_PATH = path.join(__dirname, 'helloworld.proto');
const packageDefinition = protoLoader.loadSync(PROTO_PATH, { keepCase: true, longs: String, enums: String, defaults: true, oneofs: true});
const helloProto = grpc.loadPackageDefinition(packageDefinition).helloworld;
function main() { const client = new helloProto.Greeter('localhost:50051', grpc.credentials.createInsecure());
const userName = process.argv[2] || 'Mundo';
client.sayHello({ name: userName }, (error, response) => { if (error) { console.error('Error:', error.message); return; } console.log('Respuesta del servidor:', response.message); });}
main();Ejecución y pruebas
Ejecute el servidor en una terminal:
node server.jsEn otra terminal, ejecute el cliente:
node client.js IvánDebería