Комментарии 45
Особенность 2. HTTP/2.0
HTTP/2 работает и для REST API
Объем передаваемых данных: Большой, потому что передается текст
Стоит учесть повсеместно используемый gzip и выигрыш protobuf над json на больших (больше 1 Кб) / сложных данных сведётся к 15-30%. Можно составить синтетический пример, в котором структура сообщения состоит из справочника float-чисел, в таком случае выигрыш gRPC будет максимальным.
Впрочем, это не отменяет всех прочих недостатков и преимуществ, описанных в статье, спасибо)
как по мне так оптисальный вариант - jsonRPC
Есть опыт работы с ним - плюсы/минусы в реальной жизни, подводные камни, просто некое мнение по опыту работы? Сама идея мне весьма нравится, но вживую не встречал.
да. давно использую
с одной стороны удобнее что не стопицот методов и праметров
с другой стороны там json а не бинарник
На чем написано - net, java, php, etc? Средства/стандарты для генерации документации и клиентов есть по типу свагера или wsdl?
ну есть спецификация
https://www.jsonrpc.org/specification
писать можно на чем угодно - это ж просто разобрать и сформировать json
Но . есть и готовые библиоотеки
я например использую https://github.com/datto/php-json-rpc
Спасибо. Про писать на чем угодно это понятно, я даже как-то руками SOAP собирал, но хочется автоматической генерации)
для go есть автоматическая генерация всего https://github.com/vmkteam/zenrpc
Я бы не стал приравнивать REST к RPC. REST вроде как больше ориентирован на работу с данными (CRUD операции по сути - создать / получить / обновить / удалить что-то), в то время как RPC - это именно удалённый вызов какой-то логики, любой. REST работает с ресурсами, в то время как RPC - с действиями, которые можно выполнять. Вроде как они даже в каком-то роде противоставляются друг другу - см. например вики - https://ru.wikipedia.org/wiki/REST):
REST является альтернативой RPC
Например, gRPC можно использовать для поднятия RPC канала локально, между приложением и сервисом, на одной машине. Чтобы REST для таких целей использовали - ни разу не видел.
В какой то степени согласен, но те мне менее почему CRUD операции не не могут быть RPC? Ведь вызываются они удаленно, пусть даже REST это про ресурсы, а не про действия.
В статье я говорю что любое API это RPC (мы удаленно вызываем какие то методы), разве это не так?
Смысл в том, что в случае с REST мы не вызываем методы явно, а работаем с ресурсами. Естественно, на каком-то уровне какой-то код своим запросом мы выполним, но в случае REST нам неважно, что делает этот код, до тех пор, пока он выполняет нужные нам операции с ресурсами. Например, это может быть какой-то API сервис заметок - где мы будем создавать заметки, обновлять заметки, получать их и удалять, типа такого:
GET /notes
GET /notes/{id}
PUT /notes/{id} (или POST /notes)
PATCH /notes/{id}
DELETE /notes/{id}
Т е наш API не даёт нам возможность вызвать какую-то процедуру, давая нам вместо этого возможность работать с ресурсами. В случае с RPC можно было бы сделать какой-то такой API:
POST /getAllNotes
POST /getNoteById
POST /createNote
POST /updateNote
POST /deleteNote
Т е мы своими вызовами явно выполняем какие-то конкретные действия. Теперь мы можем сделать то, что обычно в REST не делается, например:
POST /backupNotes - такой метод мог бы сделать бэкап заметок, и отправить его куда-нибудь
POST /emailNote - типа отправить заметку на почту
POST /printNote - распечатать заметку
И так далее. Конечно, для работы с ресурсами (как заметки) - REST подходит намного лучше, даже выглядит как-то красивее и лаконичнее.
REST можно противопоставлять RPC только до тех пор, пока вы не генерируете клиент по OpenAPI-спецификации. Работа через автогенерированный клиент ничем не отличается от RPC, а уж если ещё и сама спека была сгенерирована на основе реализации бека...
Если подумать - то с точки зрения клиента (пользователя API клиента) это действительно так. Вообще, в реальном коде, даже автосгенерированный клиент никто не будет использовать напрямую как есть. Будет какой-то удобный для потребителя интерфейс INotesClient
, который уже в свою очередь будет что-то куда-то мапить, и вызывать сгенерированный клиент. В тестах будет тестовая реализация. Для потребителя, соответственно, это будет выглядеть так, как будто он вызывает какие-то методы - но это не значит, что под капотом RPC (взять хотя бы тестовую реализацию). По-моему, это называется абстракция, и делать выводы по интерфейсу не совсем корректно.
Для начала, покажите мне локальный IPC на основе REST (например, когда локальный сервис при запуске говорит UI клиенту - покажи главное окно). Конечно, можно придумать синтетический пример типа `POST /displayedWindows`, интересны реальные проекты.
Абстракция абстракцией, но обратите внимание: вызов функции на клиенте приводит к вызову функции на сервере с теми же параметрами. Это буквально определение RPC.
Хорошо, если REST это RPC, жду примеров локального IPC на основе REST. Я такого почему-то никогда не видел.
Ну вот, к примеру, протокол докера (тот который между docker и dockerd)
Это вот этот вот протокол? https://docs.docker.com/reference/api/engine/version/v1.45/
Он частично REST, частично RPC, например:
POST /containers/{id}/resize
POST /containers/{id}/start
POST /containers/{id}/stop
POST /containers/{id}/restart
POST /containers/{id}/kill
POST /containers/{id}/update
POST /containers/{id}/rename
POST /containers/{id}/pause
POST /containers/{id}/unpause
И так далее. Очевидно, тут мы не выполняем CRUD операции над ресурсами, а выполняем действия. Это и есть RPC. Если бы я такой API обозвал REST на работе - меня б с позором выгнали :) Вообще, если API использует HTTP и JSON, и имеет схему OpenAPI - это ещё совсем не значит, что это REST.
Я уже выше писал что REST, вне зависимости от того как у вас там что генерируется, должен быть stateless. А RPC совсем не обязательно будет stateless. Аналогичная ситуация с кэшированием.
И поэтому как минимум в этом контексте получается что далеко не любые RPC можно реализовать через REST.
А у нас, к примеру, наоборот, на основе спеки генерируются контроллеры и классы модели данных. Тоже очень удобно.
Пишешь OpenApi 3.0 спецификацию в yaml, генерируешь классы и можешь сразу переходить к бизнес логике.
Плюс есть апи по которой фронты забирают обновленные спеки, поэтому зачастую можно передавать фронтам новые апишки без комментариев.
Эхх молодежь, а ведь CORBA, DCOM были совсем недавно, и даже не упомянули их, а какие срачеки были по их поводу, особенно когда замаячил SOAP.. (кряхтя), где-то тогда я и отчалил с этой шхуны. ;)
P.S. За статью пасиба.
В каком-то смысле можно сказать, что API и есть RPC, а REST API или gRPC — это как варианты реализации. Поэтому предлагаю здесь не останавливаться и перейти к ещё одной известной реализации удалённого вызова процедур.
REST по определению должен быть stateless и casheable . RPC совсем не обязательно должен быть stateless, а делать его casheable часто даже просто очень плохая идея.То есть вы в теории можете реализовать какое-то подмножество RPC при помощи REST. Но далеко не все варианты.
Поэтому прежде чем идти дальше я бы всё-таки предложил вам остановиться и разобраться.
имхо, если вопрос производительности не критичный, то REST с JSON выглядит более предпочтительным. куда проще потом разбирать баги, когда есть человекочитаемые данные в текстовом формате, а не кусок бинарных данных, для которого ещё схему знать надо, чтобы прочитать корректно.
Тот же Wireshark вполне себе позволяет дебажить gRPC; https://grpc.io/blog/wireshark/
Проблемы тут сразу две:
TLS - gRPC без сертификата в принципе боль. Локальная разработка превращается в цирк с конями на ровном месте.
Remote debugging - не всегда клиент и сервер для дебага можно разместить в одной сети. А если сервис на чём-то безгуёвом и в облаке, то боль умножается на 2. MitM частично решают, но не умеют в gRPC.
Вот поэтому многие и используют HTTP - на нём банально инструментарий богатый на все случаи жизни и отладки. Не говоря уже о важном факторе: схему надо знать. Без схемы не будет интеграции. Если сервер не подконтрольный, то с ним дружить не получится.
TLS - gRPC без сертификата в принципе боль
И опять же :
https://gitlab.com/wireshark/wireshark/-/wikis/How-to-Export-TLS-Master-keys-of-gRPC
https://github.com/salrashid123/grpc_sslkeylog?tab=readme-ov-file
Remote debugging - не всегда клиент и сервер для дебага можно разместить в одной сети.
Я может что-то не так понимаю, но зачем вам иметь их в одной сети чтобы использовать Wireshark?
Вот поэтому многие и используют HTTP - на нём банально инструментарий богатый на все случаи жизни и отладки.
Я не спорю что это проще. Но это не так что дебажить gRPC вот прямо совсем невозможно.
Да никто и не говорит "невозможно". Просто KISS приучает делать всё как можно проще. Зачем усложнять себе жизнь ради 10-20% прироста в сериализации, если 80% времени это запрос в БД (к примеру).
С HTTP легко можно работать в cURL и отладить запрос даже с чайника. Сделать то же самое с gRPC довольно большой геморрой. Вопрос именно в этом, о чём и речь.
Ну мы работаем с gRPC и я бы не сказал что это какой-то особый геморрой.
Более того мы его используем именно потому что в контексте эмбеддед разработки и/или необходимости работать с разными ЯП/стэками(в том числе и различными "зоопарками" на стороне заказчиков) он оказался одним из самых простых вариантов.
Как будто коллег позвали прокомментировать статью. По верхам прошлись, но так и не стало понятно как каждый из них работает.
И REST и RPC решают проблему взаимодействия между компонентами в распределенных приложениях. Я бы добавил в этот список ещё Event-driven.
REST смотрит сюда как на задачу передачи состояния. RPC - намерений совершать какие-то действия. Events, наоборот, уведомляют об уже случившемся. Выбор того или иного стиля зависит от конкретных требований (чаще - нефункциональных). При чем, разные стили можно комбинировать.
Внутри вы можете использовать любой удобный формат данных: JSON, XML, plain text или тот же protobuf - не суть. Это больше вопрос дизайна, нежели архитектуры.
Как по мне, так
между своими сервисами или стримить - gRPC
наружу что-то простое - REST
наружу что-то сложное или если надо надо шейпить - GraphQL
Из первой части статьи складывается впечатление что rest без формата json невозможен.
Собственно вопрос, а если мы не используем json или используем другой формат это уже не рест?
В начале статьи я как раз и пишу, что REST это свод правил, исполняя который вы делаете REST API, но чаще всего используется JSON и поэтому я грубо принимаю это за данность, что REST это всегда JSON. В действительности, конечено, можно использовать любой формат организации текста.
Спасибо за комментарий, нужно было более четко это подсветить!
Небольшая ремарка по поводу Protobuf. Это никак не влияет на информативность статьи, просто немного режет глаза. Protobuf также строится на принципе ключ-значение (tag - value), только в отличии от JSON, ключи (тэги) исключительно числовые. В вашем примере значения тэгов = 1, 2, и 3. Тэги также передаются по сети, и занимают от одного байта и выше (зависит от числового значения (например значения 1..15 занимают 1 байт, 16..2047 - 2 байта и т. д.)).
Но даже несмотря на это, выигрыш по отношению к JSON несомненный.
Почему-то тема идемпотентности не затронута. А между тем, при проектировании API идемпотентность - наиважнейшая вещь; пожалуй, важнее чем конкретный протокол (будь то REST, GraphQL, гРПЦ аминь и т.д.). Когда жёлудь спелый API идемпотентный, можно его хоть как гонять, хоть через Next Server Functions.
В принципы REST API можно было бы добавить HATEAOS. А также описать REST API Maturity Levels. Филдинг вообще говорит, что REST APIs must be hypertext-driven
А так же стоило бы вспомнить про спецификацию стандарта специфікація HAL (Hypermedia Application Language). HAL декларирует структуру документа, который возвращается сервером клиенту, причом ээто может быть и JSON и XML.
Клиент может в заголовке запроса Accept указать поддерживает ли он HAL или нет. А сервер сгенерирует ответ базируясь на значении этого заголовкаа. ЭЭто называется Content negotiation и входит в REST API Maturity Model Level 3.
В соотвествии со стандартом HAL-документ может содержать три вида данных:
- Resource object (т.е. представления ресурса)
- Link Objects (ссылки на операции, которые доступны клиенты для данного ресурса)
- Связанные (child або embedded) ресурсы.
Если не ошибаюсь, Фидинг считает, что "настоящий" REST API только тот, что удовлетворяет Level 3 Maturity ))
Хех, мне кажется что это статья ради статьи. Ведь в озоновской конвенции по микросервисам вроде бы было написано что все сервисы должны общаться по gRPC
пример с мультиплексированием некорректно ссылается на множество соединений. в HTTP/1.1 появился keep-alive с которым новое соединение можно не делать а продолжать общение в рамках текущего.
REST vs gRPC. Межсервисная интеграция для начинающих