Если вы сталкиваетесь с тем, что клиент «просто работает», пока бэкенд не решил переименовать поле или вернуть null там, где раньше был объект, — значит, ваш контракт существует только в переписке и в голове того, кто писал API. Новый джуниор приходит в проект и полдня читает интерсепторы, пытаясь понять, какие поля обязательны, а какие «обычно есть». Каждый релиз — это молитва, что маппинг не сломается.

На самом деле проблема не в том, что REST плохой или что вы недостаточно знаете типы. Проблема в том, что контракт между клиентом и сервером нигде не хранится как первоисточник: он размазан по докам, по коду двух команд и по ожиданиям людей. Типы в TypeScript на клиенте — это копия копии, и она устаревает в первый же день после релиза бэкенда.

Вот что важно понимать: схема, а не код, должна быть источником истины. Когда описание сервиса — это .proto, из которого codegen даёт и сервер, и клиент, то «поле исчезло» перестаёт быть сюрпризом: компилятор ругается ещё до прода. Это не про gRPC как транспорт, а про дисциплину: контракт, версионирование, статусы ошибок и deadline решаются один раз и потом просто работают.

⚙️ Разобрать это на реальных кейсах — Protobuf, codegen, стриминг, ошибки и mTLS — можно в курсе gRPC и контракты: первый модуль бесплатно. Подписывайтесь — дальше разбираем архитектуру без воды.