Я всю жизнь писал только бэк и подкапотщину - будь это классический КРУД, хайлоад, CLI, [вставьте свое]... И для любых сетевых взаимодействий чаще всего люди думают именно прикладными вещами - GRPC, REST, Kafka, не задумываясь об этом глубже - супер удобные инструменты с защитами от дураков и прочими радостями

Но тут спохватился я писать фронт - подключать свое же к себе же. И в этот момент я понял, насколько же это сложно, муторно и, главное, НЕУДОБНО взаимодействовать REST'ом

ЗАЧЕМ ОН НУЖЕН?? - У нас нет удобного контракта общения (eg Proto, Avro) кроме Swagger, который нужно поддерживать с обеих сторон. Да и к тому-же, сложность взаимодействия с JSONом с ОБЕИХ СТОРОН - одна постоянно маршаллит, защищается, ищет поля, в то время другая боится резких обновлений, что строчка получения поля может превратиться в что-то вроде

resp?.body?[i]?.creds?.card?.number

В этот момент у меня возник вопрос: если gRPC решает эти проблемы, почему мы не используем его на фронте?

Попытки решения отсутствия контрактов

не буду вдаваться в подробности, большинство их +- трогало или знают, распишу плюсы и минусы подходов

Codegen/OpenApi/Swagger

Запихну это все в одно и напишу кратко - ЭТО НИКОГДА НИЧЕГО НЕ ГАРАНТИРУЕТ.

Фронт резко открыл код, сделал запрос, а там уже разраб, который ушел в отпуск, уже все поля красиво поменял, Сваггер не обновил и никому ничего не сказал.

Вы скажете - «Ну проблема в плохой организации работы» - как бы да, но у всех бывают дни, когда чо-то идет не так, мы все люди))

GraphQL

Известная голубая компания ЛицоКнига когда-то решила проблемы разработчиков интерфейсов - строгая схема, типизация, codegen, introspection

Фронтендеры были относительно счастливы (хотя и своих бед с GQL хватало), но кому явно досталось - бэк
Разработчики серверной части лишились КОНТРОЛЯ

  1. клиент сам выбирает, что ему нужно и в каком количестве

    сегодня это было

    { user { id name } }

    а завтра станет

    { user { posts { comments { author { posts { comments { … } } } } } } }

    по итогу ты опять созваниваешься с фронтом и говоришь «Это дергай, а это старайся не дергать»

  2. отсутствует прямое соответствие моделям данных

    резолверы, маппинг, аггрегации, не дай бог юнион тайпы - вокруг всего теперь танцую Я, а не ОН

  3. N+1

    Почти везде, почти всегда

Да, эти проблемы решаются - DataLoader закрывает N+1, persisted queries и depth limiting ограничивают клиента. Но каждое из этих решений - это дополнительный слой сложности на бэке, которого не было с REST
Про неудобство в некоторых языках я вообще молчу (гляньте пакет на го)

gRPC-Web

Так вот же оно! К чему статья??

Надеюсь, что я не многих удивлю, но это - ненастоящий gRPC

Это - лютейшего вида trade-off! Да, с виду у нас все есть: Protobuf, codegen, контракт. А что под капотом?

Отсутствие полноценного HTTP/2

Да, все верно. Хоть браузеры давно поддерживают даже 3ю версию протокола, но полного контроля нам никто не давал. А это значит, что мы теряем

  1. Опять Контроль - мы НЕ управляем соединением, НЕ управляем фреймами, НЕ управляем стримами. Клиент даже не знает, какую версию HTTP изволит использовать браузер, это выглядит как обычный fetch

    fetch(“/api”)

  2. Одни из самых главных фишек HTTP/2 - управление мультиплексированием и бинарными фреймы.

    Браузер → прокси работает по HTTP/1.1, зато прокси → бэк использует полноценный HTTP/2. Выигрыш есть, но только на конце - там, где нам он нужен меньше всего

  3. Просто с места ничего не заработает - нужна инфраструктура, которые это будет поддерживать (как минимум Proxy, который это будет правильно принимать и понимать)

Итог: gRPC перестаёт быть транспортом и превращается в формат данных. Мы приобретаем лишь гемор без плюсов. Как говорил один классик:

Можно. А зачем?

А почему так-то?

Тут и стало понятно - проблема не в REST, не в GraphQL и даже не в gRPC

Главная проблема - САМ БРАУЗЕР

Ответ почему так получилось крайне прост - БЕЗОПАСНОСТЬ, а возможно даже параноидальность

Каждый раз заходя на любой сайт мы запускаем код на своем устройстве: с любого источника, от любого автора, с доступом к сети

Если мы дадим ПОЛНЫЙ ДОСТУП к HTTP/2-3, мы соответственно даем также доступ к

  • Любым TCP соединениям

  • Любым долгоживущим соединениям

  • Управлению HTTP/2 фреймам с плохим умыслом

А с таким набором инструментов на любом ПК мы можем

  • сканировать внутреннюю сеть пользователя

  • ломиться в localhost

  • обходить firewall

  • устраивать DDoS чужими руками

А почему с HTTP/1.1 нет проблем?

Тут два главных столпа

  1. Sandbox

    JS работает в своей песочнице, в которой нет доступа ни к сокетам, ни к файловой системе (ну почти), к процессам и вообще ограничен контроль над сетью

  2. Абстракция

    Нам дают маленький набор инструментов (и тот ограничен, как к пр. WebSocket). Браузер все решает САМ

Тогда в принципе зачем браузеру нужны HTTP/2-3?

Примерно тут уже в голове небольшой диссонанс - если все фичи заблокированы, то тогда зачем они в принципе существуют?

А все крайне просто - HTTP/2-3, QUIC и прочие радости существуют не для кода, исполняемого в браузере, а для самого браузера. Мы не можем пользоваться этим самим, а он все сам решает

  • мультиплексирование

  • сжатие заголовков

  • бинарный формат

    и многое другое, но все ведет к одному - только для ускорения самому, и не более

Панацея (или что с этим делать)

Редко, но можно найти в использовании красивые лаконичные решения

  1. tRPC

    если у тебя монорепо TypeScript, это почти идеальный контракт без кодогенерации. Работает поверх обычного HTTP, типы шарятся напрямую через импорт

  2. Connect protocol (от Buf)

    адстройка над gRPC, которая умеет работать с обычным fetch. Официально поддерживается в браузере, имеет нормальный codegen

  3. WebTransport

    экспериментальный API, который даёт браузеру доступ к HTTP/3 потокам в sandboxed режиме. Пока сырой, но это именно то направление, куда движется индустрия

Что в итоге?

Альтернативы существуют - tRPC, Connect, WebTransport. Но REST никуда не уйдёт в ближайшее время, потому что универсальность важнее удобства. Браузерные ограничения - это симптом, а корень глубже: мы до сих пор не договорились, кто отвечает за контракт (да, мы тоже в этом виноваты)

Но все идет вперед. WebTransport потихоньку стабилизируется и даёт браузеру то, чего у него никогда не было - доступ к потокам поверх HTTP/3 в sandboxed режиме. Connect protocol от Buf набирает комьюнити, а TypeScript-монорепозитории с tRPC уже сейчас показывают, как выглядит мир без ручного поддержания контрактов (хоть и крайне редко)

Возможно, через пять лет мы будем смотреть на голый REST так же, как сейчас смотрим на XML-RPC. А возможно - нет, и curl останется главным инструментом отладки ещё очень долго

Также буду благодарен за подписку на мой тгк, если вам близки такие мини статьи и факты из моего личного опыта работы)

Только зарегистрированные пользователи могут участвовать в опросе. Войдите, пожалуйста.
Что у вас на проекте?
90.91%REST30
6.06%SOAP2
6.06%gRPC-Web2
3.03%tRPC1
3.03%Connect Protocol1
3.03%GraphQL1
Проголосовали 33 пользователя. Воздержались 8 пользователей.