gRPC для TypeScript: библиотеки и примеры
gRPC — это высокопроизводительный RPC-фреймворк от Google, работающий поверх HTTP/2 и использующий Protocol Buffers (protobuf) для сериализации данных. В TypeScript (и Node.js) gRPC позволяет строить эффективные микросервисные архитектуры с поддержкой стримов и двунаправленной связи. На этой странице мы разберём основные библиотеки, настройку рабочего окружения и напишем работающий пример клиент-серверного приложения.
Основные библиотеки для gRPC в TypeScript
Для работы с gRPC в экосистеме TypeScript существует три ключевых пакета:
@grpc/grpc-js— чистая JavaScript-реализация gRPC (без нативных зависимостей), полностью поддерживает HTTP/2 и работает в Node.js 12+.@grpc/proto-loader— загрузчик.protoфайлов, динамически создающий JavaScript-классы на основе определений protobuf.ts-proto— генератор TypeScript-типов из proto-файлов. Альтернатива встроенномуgrpc-tools, но с лучшей поддержкой строгой типизации.
Установка всех компонентов одной командой:
npm install @grpc/grpc-js @grpc/proto-loader ts-proto
npm install -D typescript @types/node
Создание .proto файла
Начнём с определения сервиса. Создайте файл hello.proto:
syntax = "proto3";
package hello;
service Greeter {
rpc SayHello (HelloRequest) returns (HelloReply);
rpc SayHelloStream (HelloRequest) returns (stream HelloReply);
}
message HelloRequest {
string name = 1;
}
message HelloReply {
string message = 1;
}
Генерация TypeScript-типов с ts-proto
ts-proto создаёт полноценные интерфейсы и классы сообщений. Установите protoc и плагин:
npm install -g protoc-gen-ts-proto
protoc --ts_proto_out=./generated hello.proto
В результате получится файл generated/hello.ts с интерфейсами HelloRequest, HelloReply и типизированным сервисом GreeterClient.
Серверная часть (gRPC сервер на TypeScript)
Создайте файл server.ts:
import * as grpc from '@grpc/grpc-js';
import * as protoLoader from '@grpc/proto-loader';
import { ProtoGrpcType } from './generated/hello';
const packageDef = protoLoader.loadSync('hello.proto');
const grpcObj = (grpc.loadPackageDefinition(packageDef) as unknown) as ProtoGrpcType;
const server = new grpc.Server();
server.addService(grpcObj.hello.Greeter.service, {
SayHello: (call: any, callback: any) => {
const name = call.request.name;
callback(null, { message: `Привет, ${name}!` });
},
SayHelloStream: (call: any) => {
const name = call.request.name;
for (let i = 0; i < 5; i++) {
call.write({ message: `Сообщение ${i + 1} для ${name}` });
}
call.end();
}
});
server.bindAsync('0.0.0.0:50051', grpc.ServerCredentials.createInsecure(), () => {
console.log('Сервер запущен на порту 50051');
});
Клиентская часть (gRPC клиент на TypeScript)
Создайте файл client.ts:
import * as grpc from '@grpc/grpc-js';
import * as protoLoader from '@grpc/proto-loader';
import { ProtoGrpcType } from './generated/hello';
const packageDef = protoLoader.loadSync('hello.proto');
const grpcObj = (grpc.loadPackageDefinition(packageDef) as unknown) as ProtoGrpcType;
const client = new grpcObj.hello.Greeter(
'localhost:50051',
grpc.credentials.createInsecure()
);
// Унарный вызов
client.SayHello({ name: 'Алиса' }, (err, response) => {
if (!err) console.log('Ответ:', response?.message);
});
// Server-streaming вызов
const stream = client.SayHelloStream({ name: 'Боб' });
stream.on('data', (data) => console.log('Стрим:', data.message));
stream.on('end', () => console.log('Стрим завершён'));
Особенности работы с TypeScript
При использовании @grpc/proto-loader типы генерируются динамически, что может привести к потере строгой типизации. Рекомендуется:
- Использовать
ts-protoдля статической генерации интерфейсов. - Применять