Введение: REST умер? Да здравствует gRPC!
Вы когда-нибудь ловили себя на мысли, что ваш REST API работает как старая почта — отправил запрос и ждёшь ответа, а потом ещё и парсишь JSON, который весит больше, чем сами данные? Если да, то добро пожаловать в мир gRPC в TypeScript. Эта технология обещает скорость, строгость типов и потоковую передачу данных. Но, как и любой мощный инструмент, gRPC — не серебряная пуля. В этой статье мы разберём, когда его стоит использовать, а когда лучше остаться на привычном REST. И всё это — с живыми примерами на TypeScript, потому что сухая теория — это скучно.
Мы поговорим о том, как gRPC меняет правила игры в микросервисах, почему Protobuf — это не просто "ещё один формат", и как TypeScript помогает нам не потеряться в этом зоопарке типов. Поехали!
Что такое gRPC и почему он подружился с TypeScript?
gRPC — это фреймворк для удалённого вызова процедур (RPC), разработанный Google. Вместо того чтобы слать HTTP-запросы с JSON, вы определяете сервисы и сообщения в файлах .proto (Protocol Buffers), а затем генерируете клиентский и серверный код. Основные фишки: бинарный формат данных, поддержка стримов (streaming), строгая типизация и двусторонняя связь.
А теперь представьте, что вы пишете на TypeScript. У вас уже есть статическая типизация, но в REST API она часто "ломается" на границе с JSON. gRPC в TypeScript решает эту проблему кардинально: типы генерируются из .proto файлов автоматически. Вы больше не гадаете, что пришло в ответе — компилятор TypeScript скажет вам об этом на этапе разработки.
Почему TypeScript — идеальная пара для gRPC?
- Единая экосистема типов: Protobuf-типы превращаются в интерфейсы TypeScript. Никаких
anyиas any. - Автодополнение: Ваша IDE понимает все поля запросов и ответов.
- Безопасность рефакторинга: Переименовали поле в
.proto? TypeScript подсветит все места, где оно используется.
Когда gRPC в TypeScript — это выбор чемпионов?
Не каждый проект требует gRPC. Но есть сценарии, где он даёт 10-кратный прирост производительности и удобства. Давайте разберём их по порядку.
1. Микросервисы на TypeScript: внутренняя коммуникация
Если у вас 5–10 микросервисов на TypeScript, которые постоянно общаются друг с другом, gRPC — ваш лучший друг. Представьте: сервис пользователей передаёт данные сервису заказов. Без gRPC вы бы сериализовали JSON, десериализовали, проверяли типы вручную. С gRPC это происходит на уровне протокола.
Пример простого сервиса:
// user.proto
service UserService {
rpc GetUser (GetUserRequest) returns (User);
}
message GetUserRequest {
string user_id = 1;
}
message User {
string id = 1;
string name = 2;
string email = 3;
}
После генерации кода вы получаете строго типизированный клиент:
import { UserServiceClient } from './generated/user_grpc_pb';
import { GetUserRequest } from './generated/user_pb';
const client = new UserServiceClient('localhost:50051', grpc.credentials.createInsecure());
const request = new GetUserRequest();
request.setUserId('123');
client.getUser(request, (error, user) => {
if (!error) {
console.log(user.getName()); // TypeScript знает, что это string
}
});
Когда использовать: когда каждый миллисекунд задержки между сервисами критичен (например, в финансовых системах или игровых серверах).
2. Потоковая передача данных (Streaming)
REST не умеет нормально стримить. WebSocket — умеет, но это другой протокол. gRPC поддерживает четыре типа стримов: однонаправленный (клиент->сервер), серверный (сервер->клиент) и двунаправленный.
Допустим, вы пишете чат-приложение на TypeScript. REST API с polling (опросом) — это прошлый век. gRPC с двунаправленным стримом — то, что нужно.
// chat.proto
service ChatService {
rpc Chat (stream ChatMessage) returns (stream ChatMessage);
}
message ChatMessage {
string user = 1;
string text = 2;
}
Клиент на TypeScript:
const call = client.chat();
call.on('data', (message: ChatMessage) => {
console.log(`[${message.getUser()}]: ${message.getText()}`);
});
call.write(new ChatMessage().setUser('Alice').setText('Привет!'));
call.end();
Когда использовать: аналитика в реальном времени, трекинг местоположения, лайв-трансляции, финансовые тикеры.
3. Мобильные приложения и low-power устройства
Бинарный формат Protobuf значительно компактнее JSON. Если ваше приложение на TypeScript (через React Native или Node.js) работает на медленных каналах связи, gRPC может сэкономить до 30–40% трафика. Это особенно важно для IoT-устройств или приложений с лимитированным интернетом.
4. Полиглотные системы (когда бэкенд на Go, а фронтенд на TypeScript)
gRPC — это не про язык. Вы определяете контракт в .proto, а код генерируется для Go, Java, Python, TypeScript — всего более десятка языков. Если ваш бэкенд на Go, а клиент на TypeScript (например, Node.js сервер), gRPC обеспечивает идеальную совместимость.
Когда НЕ стоит использовать gRPC в TypeScript?
Было бы нечестно рассказывать только о плюсах. Давайте посмотрим на обратную сторону медали.
1. Публичные REST API для внешних потребителей
Если ваш API будут вызывать сторонние разработчики (браузеры, мобильные приложения, которые вы не контролируете), gRPC — это головная боль. gRPC Web всё ещё требует прокси-сервер (например, Envoy) и не поддерживается нативно в браузерах. REST + OpenAPI/Swagger здесь — стандарт де-факто.
2. Простые CRUD-приложения
Если у вас 3–4 сущности и простые запросы "создать-прочитать-обновить-удалить", gRPC окажется избыточным. Вы потратите время на настройку .proto файлов, генерацию кода и разворачивание прокси. REST с Express.js и TypeScript будет быстрее в разработке.
3. Команды, не знакомые с Protobuf
Обучение всей команды работе с .proto файлами, генерацией кода и отладкой бинарных протоколов — это инвестиция. Если у вас стартап из 2 человек, который хочет выпустить MVP