Pull to refresh

Comments 38

"текстовый формат JSON, который не сжимается" - ORLY? Если вы имели в виду, что сжатие не предусмотрено самим REST - так и надо было писать. Потому что тот же HTTP, поверх которого сделан REST, сжатие поддерживает.

Преимущества REST: простота, ориентация на человека. За это любят REST. Бинарные протоколы и до этого существовали, например Hessian. Более сложные технологии до этого существовали, например "Веб Сервисы". Чтобы работать с рест не обязательно использовать "Стороннее программное обеспечение", но есть инфраструктура, делающая REST "больше чем протокол". Простота, не зависимость, открытость для людей и машин - главная идея REST.

может уже пора закопать стюардессу?

Извините, но по части аргументации местами написана откровенная ахинея. Да и код вам бы подправить, а то какая-то кривая копипаста, без стилевого оформления и с левыми "1 reference".

Реальный плюс GRPC всего один: использование одного HTTP/2 соединения для отправки множества запросов. Это ускоряет отправку запросов и получение ответов. Для REST это также никто не запрещает делать, но в дикой природе гораздо чаще встречается HTTP/1, который гораздо легче разбирать.

protobuf - формат неплохой, но не самый лучший. Например, по задумке авторов поля не могут быть nullable, что не всегда удобно. Существуют только примитивные типы, которые нужно вручную преобразовывать в нужный (та же дата/время, например). Да, в JSON типов еще меньше, но при этом в большинстве REST-фреймворков существует встроенная сериализация/десериализация для многих стандартных типов. В protobuf - нифига, бери строковое значение из поля и парси вручную.

Генерация кода... Да, можно сгенерировать код клиентской библиотеки и серверный бойлерплейт для многих языков. Но этот код зачастую сложен для понимания и анализа, в связи с чем IDE не всегда может адекватно сформировать подсказки по методам и полям. И чем это отличается от генерации кода для OpenAPI? Это притом, что OpenAPI часто генерируется автоматически на основе аннотаций в коде, и в нем можно указать гораздо больше различных данных: описания методов и полей, авторизация для методов, валидация передаваемых данных и т. п.

Обработка ошибок в GRPC тоже выглядит странновато. Если метод кидает исключение - не факт, что GRPC его отловит и вернет ошибку. Вместо этого нужно перехватывать исключения вручную и возвращать ошибки специальным способом - причем разным для каждого языка (то есть нельзя писать серверное приложение на Python, а потом с этим же опытом прийти в Go, GRPC API будет чувствительно различаться).

Все остальное - трассировка, health check, балансировка нагрузки, аутентификация и т. п. - либо не зависит от выбора "GRPC или REST", либо банально проще и удобнее в REST. Например, во многих REST-фреймворках есть интеграция с Prometheus, а для health check не нужно заводить отдельный класс. Балансировка нагрузки и аутентификация относятся скорее к API gateway (nginx/krakend/kong/tyc etc.) и к service mesh (istio etc.), а авторизация не доставляет проблем ни там, ни там.

Вполне возможно, что я где-то не прав, сужу чисто по личному опыту.

Например, по задумке авторов поля не могут быть nullable, что не всегда удобно.

Это не совсем так, там есть набор well known types, которые можно использовать вроде бы без необходимости их как-то специально подключать. Для них генератор правильно создаёт nullable типы.

Пардон, поправка: тривиальные типы (типа string, int и т. п.) не могут быть nullable. Вложенные сообщения - могут. Для этого в well-known types как раз и сделаны типы наподобие Int64Value. Скорее всего, авторы в этом плане ориентировались на Go, где такая же логика и аналогичные типы для работы с sql.

Просто это сделано не слишком логично, учитывая наличие ключевых слов required и optional - благо от этого решили отказаться в третьей версии protobuf.

Что значит nullable?

В proto3 спецификации все поля - optional, то есть могут либо быть либо отсутствовать. Чем это отличается от nullable?

Тем что отсутсвие поя и null это разные вещи.

Например рассмотрим метод PUT, который должен обновлять только переданные поля. Поэтому когда поля нет - мы его не трогаем, а когда оно есть мы его обновляем. И null это тоже значение, на которое нужно поменять.

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

ЗЫ: Если проще - пустая строка и null это тоже разные вещи, правда у некоторых это тоже не так. :)

Это потому что сообщения имеют схему, т.е. типизированы.
Наример, на C# null-able поле 'data' может быть null, но не может «отсутствовать»:
public class UpdateDTO
{
    int id;
    int? data;
}

Если же имитировать rest с его json, то логично передавать
Dictionary<string, object>

и там действительно можно различить null в поле от отсутствия поля. И такое можно устроить в protobuf, но это ж лишние накладные расходы.

Пример для явы (в c# скорее всего есть аналог)

class UpdateDto {
  Optional<Integer> id;
  Optional<Integer> data;
}

При десериализации если поля не было, то там останется null. Если поле было, то создастся экземпляр Optional с соответствующим значением - т.е оно будет или пусто или реальное значение.

Результат - есть отсутствие/присутсвие, в присутсвующих есть null/значение. Есть конкретная структура с полями. Это именно то что и требовалось.

В этом примере используются не только примитивные типы, но и класс-обёртка Optional.

Так, пожалуйста, никто не мешает в proto-файле объявить тип OptionalInteger, в котором может отсутствовать или присутствовать integer, он сам может быть optional в нашем UpdateDTO. Таким образом, мы реализуем все 3 варианта: int-значение, null-значение, отсутствие значения.
Местами и у Вас ахинея написана, не накидывайтесь уж так категорично на автора :)

Не спорю, легко могу ошибаться, и буду действительно благодарен, если объясните, в чем именно.

Относительно тривиальных типов (string, int, etc.) в третьей версии protobuf при указании optional можно получить nullable (в Golang будет сгенерировано в *string, *int, etc.). Можно ещё чуть костыляво делать через oneof, если вдруг генераторы не поддерживают optional (по типу Twirp).

А вообще действительно protobuf немного не логичный в этом плане т.к. в 3-ей версии все поля считаются опциональными, но есть ещё флаг optional, который влияет на генерируемый код. Возможно относительно скоро станет по лучше т.к. в исходниках уже появилось упоминание 4-ой версии.

Относительно самого gRPC он на самом деле не прибит к protobuf жёстко, можно поставить кодек хоть под Apache Thrift, хоть JSON, хоть MsgPack, да любой формат в целом.

Да и к транспорту по сути gRPC тоже не прибит. Например, не потоковые вызовы можно на прямую пробросить с HTTP/1.* просто подменив номер версии на HTTP/2 (это в Golang). Или можно переложить gRPC на Quic/HTTP/3 (да кода готового нет и его нужно написать).

Тем не менее - самое главное чтобы клиент знал особенности сервера. А gRPC по сути описывает формат взаимодействия (обычные/потоковые методы), это только набор соглашений.

Относительно REST у gRPC есть grpc-gateway и расширения в protobuf с которыми можно реализовать по мимо gRPC ещё и REST (как и делает сам Google). Для этого даже есть генератор схемы OpenAPI из proto файлов.

Это всё к тому, что gRPC обычно рассматривают с одной стороны. По факту даже все фичи кодогенерации к gRPC на прямую не имеют отношения, это скорее часть Protocol Buffers, чем gRPC как таковой.

В любом случае для применения той или иной технологии нужно взвешивать все за и против. Тот же GraphQL тоже нужно уметь и знать как использовать и главное где использовать.

P.S.: Так если посмотреть HTTP по своей сути тоже можно отнести к RPC, только с ограниченным набором методов GET/POST/etc. и с упором на адрес ресурса.

в третьей версии protobuf при указании optional можно получить nullable
Да, через optional можно превратить примитивные типы и string в nullable. Но я не понял, как канонично отличать передачу пустого списка от передачи null в списке. Например, я хочу сделать proto-файл для
public class MyRequest
{
    public List<int> IdList;
}
и сделать так, чтобы пустой IdList и null-значение оставались различными при сериализации в protobuf и обратно. Для моего приложения это критично.
UFO just landed and posted this here

Могу посоветовать довольно неплохой клиент Wombat. Сам же GRPC - это по сути те же HTTP/2 запросы, можно так же смотреть через tcpflow.

На фронт лучше гонять json, который там нативен. grpc, мне кажется больше применим для межсервисного взаимодействия.

UFO just landed and posted this here

Я правильно понял, что в качестве аргумента ЗА gRPC автор предлагает использовать новый язык описания API в отдельном файле, вместо обрамления методов аннотациями и авто-генерирования swagger документации по коду на лету?

Именно. Когда у вас несколько клиентов на нескольких языках, то очевидно, что сгенерировать клиентские либы удобно из одного файла protobuf.

Если я все верно понял, то в вашем сценарии, при изменении API, мне необходимо поменять protobuf файл, потом привести в соответствие сервер, а потом перегенерить клиенты.

В моем сценарии, я меняю сервер, генерирую по нему swagger из аннотаций, и на его основе генерирую клиенты. На одно действие меньше, вроде как?

В вашем сценарии не меньше, а ровно столько же.

Protobuf это контракт независимый от языка.

Иногда бывает удобно, в микросервисной архитектуре, держать контракты отдельно.

Как, собственно, и сваггер. Для него тоже кодогенераторы есть для любого популярного языка

Интересно есть плагин чтобы из браузера просматривать запросы/ответы в удобоваримом виде?

Плюс для простых случаев, для REST можно через какой-нибудь API прокси делать интересные вещи без изменений бэкенда, а с протобуфером конечно сильно сложнее по сравнению с json.

Для манипулирования данными гораздо интереснее конечно что-то типа odata/graphql.

Ну и самый большой недостаток, людей знающих как это всё заставить взлететь сильно меньше, так что если это не твой личный проект, то десять раз подумаешь прежде чем вкорячивать подобное.

Если вы про документацию api (swagger.json), то .proto файлы имеют тот же смысл. Если вы про аналог swashbuckle для code-first и генирации документации, то есть такая библиотека protobuf-net

Почему-то никто не заострил внимание, что gPRC, это не фреймворк, а технология. И автор рассматривает конкретную имплементацию этой технологии для dotnet core.

Смешались в кучу кони, люди, мухи и котлеты

Я правильно понял, что по сути

gRPC = JSON RPC + плюшки HTTP/2

?

Шёл 2021 год. Староверы из секты .net перешли с REST на RPC.

REST - не фреймворк. То есть сравнивается набор правил с фреймворком.

Про сериализацию - вообще молчу, это прям какая-то магия для меня - передача данных по сети без сериализации. Если хотите сказать, что этим вопросом занимается сгенерированный protobuf код вместо разработчика, то так и надо говорить.

С каких пор JSON стал прибит гвоздями к REST? Что мне мешает использовать XML, YAML, да даже тот же protobuf или, вовсе, свой собственный формат? Про то, что JSON ещё как сжимается выше уже упомянули.

Как видим на схеме, у клиента и сервера есть дополнительный уровень в общении — клиентская и серверная заглушки.

А где схема-то?

Про балансировку и остальное уже сказали до меня.

gRPC некорректно сравнивать с REST, потому что первое - протокол и фреймфорк для него, а второе - паттерн/методология. Мы же не сравниваем что лучше, ехать на автомобиле и ехать быстро. Можно легко имплементировать REST API при помощи gRPC в абсолютно строгом смысле.

Сравнивать нужно либо RPC vs REST (две методологии), либо gRPC и (чистый) HTTP (два протокола).

RPC (методолгия), если прикинуть в терминах теории множеств, - это надмножество REST. Рисуем кружочек с RPC, и кружочек с REST полностью содержится в нем и не выпирает. В RPC можно творить что угодно (это и плюс и минус), а в REST у вас система ограничений. RPC - это любые глаголы (verbs), REST - это четыре глагола. RPC - это хоть про ресурсы, хоть про операции, REST - только про уникально-идентефицируцемые ресуры (если придерживаться строгой формулировки). RPC - это хоть с состоянием, хоть без, REST - только без состояния. RPC - это любые типа/бинарка, REST - это известные типы. RPC - это любая семантика связей между чем-угодно, REST - линки между ресурсами. То есть здесь немного неочевидно ставить слово "или" ("vs.") между ними, вы можете иметь протокол, который принадлежит и REST и RPC, хотя традиционно так никто не думает. Кстати, "запихуивание" операций и состояния в REST API забирает у нас право называться REST API, если строго. Этим вообще грешит больше половины "REST" API. Обнаружили аля /operations/start - все, это не REST. RPC - это про делать (что угодно и как угодно), REST - про хранить и изменять ресурсы в системе ограничений.

gRPC vs. HTTP, тут уже надо смотреть что именно мы сравниваем. gRPC (протокол) это и transport-agnostic, и бинарка, и в обе стороны, и стриминг. Кроме того, он умеет летать поверх HTTP (что опять же делает слово "или" неуместным, можно иметь и HTTP и gRPC одновременно). gRPC (фреймфорк) - это contract-first, код-генерация, кросс-платформенность. А HTTP - вообще не фреймворк.

Один из примеров gRPC - api для telegram ботов. Второй пример API к VK. Под капотом в обоих случаях чистый JSON. Так что связка с protobuf совсем не обязательная вещь.

Что касается ошибок? А как в gRPC о них сообщает сервис, как и различать? Вводятся какие то внутренние коды или есть иной механизм? Как отличить недостаток прав/истечение срока авторизации/внутреннюю ошибку сервиса.

Вот пессимист внутри меня отказывается верить в розовый мир в котором в сервисах нет багов и все обращаются только туда куда можно

И вопрос откуда вы код то брали?

0 => o.Address = new Uri ( “https://localhost :500 “) ;

На входе ноль(что есть не корректное именование переменной в шарпе), а в коде o. Понятно что очипятка но таких прям не мало

Насколько я понял ребята изобрели Remote Method Invocation, но только доступный не исключительно для Java? М-м-м.. Знаете что то мне...

REST и gRPC: ключевые отличия

Чтобы лучше понять принципиальную разницу между этими фреймворками,

Ой все.

Сколько раз обговаривалось, что REST, это архитектура. Ее можно реализовать любым фреймворком, или без него вовсе! Любой технологией, будь то HTTP (по определенным причинам наиболее подходящий для этого) или почта, да хоть по телефонной линии передавай!

Сравнивая гугловскую технологию с REST,

Единственное упоминание того с чем конкретно идет сравнение в статье.
(Ы.З. Не нашел в первой пятерке выдачи поисковика, инфу про "гугловскую технологию с REST" по этому насколько актуально сравнение - не скажу)

Подведем итоги:
1) Автор намеренно путает понятия технологии и архитектуры, вводя читателя в замешательство
2) Статья суть реклама продукта, который представляет собой изобретенный велосипед. Ну да, передач побольше, рама покрепче - круто. Но не нужно преподносить новый велосипед, как что то инновационное. Лучше рассказать чем ваш мопед лучше других вместо пустых и громких слов.
3) Пункт выше направлен больше не к содержанию статьи, а к ее основной идее. (и кликбейтному заголовку). А следовательно в содержании статьи были интересные моменты, например сделать "фреймворк" под разные языки - довольно оригинально, оправдает ли оно себя? Не знаю. Использование современных стандартов в замен устаревших? Плюс, но очень слабый, т.к. и REST можно реализовать с использованием всего перечисленного. Вот то что это уже идет из коробки - да не плохо.

Что мы имеем:

+) Автора похвалить за презентацию любопытного продукта

-) Пожурить за запудривание аудитории с целью приукрасить.

Автор вышел в ноль, с чем я его и поздравляю, а я пойду сёрфить дальше.

Sign up to leave a comment.