All streams
Search
Write a publication
Pull to refresh

Comments 15

вы пару раз критически упоминули json-rpc 2.0, но не раскрыли в чём его минусы.

Почему там всегда 200 понятно - изза батчинга. А что ещё?

Один из недостатков: json-rpc в спецификации не гарантирует порядок результатов при пакетных запросах. Но я бы не сказал, что это фатально. Если разработчику важен порядок в массиве результатов, то он просто учтет этот момент у себя в коде. То, что нет четко закреплённого списка ошибок - тоже спорный момент.

Статус 200 - это просто успешный транспорт payload. И дело тут не в батчинге.

Вместо фиксации порядка в JSON-RPC 2.0 используется id запроса, который возвращается в ответе.
Некоторый фиксированный набор ошибок там тоже есть, он связан с ошибками в самом протоколе. Ошибки приложения разработчик определяет сам.

Я вовсе не критиковал json-rpc 2.0, а лишь приводил его, как противовес. Но не рассматривал его как альтернативу, потому что и в нем всё не так, как разработчикам хотелось бы интуитивно. Он не плохой, со своими задачами справляется, но, как сказал Билли, в исполнении Караченцова, в фильме Человек с бульвара капуцинов:

Вот так мы отдыхаем, Джонни. А душе хочется чего-то другого: светлого, большого...

Каждый раз в статье, упоминая про json-rpc 2.0, я лишь подчеркиваю, что большинство реализаций псевдо-REST это по факту какой-то JSON-RPC или HTTP-RPC или как-то иначе его назвать, но он ничего не имеет общего с json-rpc 2.0, вот какая мысль звучит в статье. Название json-rpc уже занято.

Но, на мой взгляд, это как-то очень скучно и сухо.

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

Ваш личный опыт - самый правильный учитель :)

Я лишь поделился своим опытом и наблюдениями, быть может, они окажутся полезными тем, у кого своего опыта недостаточно.

Статья бьет типичным реализациям не в бровь, а в глаз! Однако я не согласен с выводами и частью советов.

Труъ RESTful – весьма специфичная штука, которая хорошо подходит для CRUD, но плохо для процессинга.

Суть REST в том, что если процессинг представить как CRUD, то получаем доступ к возможностям, которые очень полезны для долгоживущих открытых систем в неидеальной сети. Заменив процедурный вызов "обработать" на ресурс "обработка", мы можем естественным образом сделать: просмотр результатов обработки после её завершения (GET) с кэшированием, устойчивый к обрыву связи идемпотентный запуск (PUT), запрос "есть чё?" (HEAD).

Вы предлагаете включать лампочку через POST. Запрос упал по тайм-ауту. Что будет, если отправить его заново — ошибка "уже включена"? успех? А вот клиенту надо логировать успешные включения, автор API предусмотрел в ответе признак, нами ли она включена и когда? REST через HTTP позволяет всё это решить стандартными средствами, достаточно соблюдать семантику глаголов. Даже если не соблюсти сразу, то из стандарта известно, как должно быть (conditional PUT). Реализуем — и не надо рассказывать, как пользоваться этим именно в нашем API.

REST задумывался так, чтобы перенести глаголы из URI в HTTP-методы, а часть параметров из тела в URI. Разумеется, это удобно, когда можно обратиться к одному и тому же URI, но с разными HTTP-методами и результат будет разным.

Вы этими словами противоречите собственному абстрактному, правильному описанию REST из начала статьи. Очевидно, что над бизнес-сущностью могут быть возможны операции, которые глаголами HTTP напрямую не описываются. Проблема в том, что семантика этих операций специфична для API. Клиенты её не знают; хуже того, сам автор мог не всё продумать, как в примере с лампочкой. Задумка REST в том, чтобы свести все операции к набору стандартных. С параметрами происходит следующее: есть "что" — субъект операции, которого мы идентифицируем (I в URI), а есть "как" — именно параметры конкретной операции. Разделение нужно, в основном, чтобы по URI кэшировать.

Насчет психологии процитирую умного человека:

RPC людям нравится не за то, что у него есть преимущества, а за то, что они не сразу видят его недостатки.

Отличное замечание. Спасибо за уточнение философской глубины подхода!

Однако я сознательно упростил формулировку.

Моя цель была показать практическую разницу, которую видит разработчик при переходе от RPC к REST.

Технически вы правы - REST это не просто "перенос", а смена парадигмы.
Но психологически для разработчика это выглядит именно как "перенос глаголов". Большинство разработчиков не вникали в суть философии REST, отсюда и такие реализации. Повторюсь - REST очень красив, но у него высокий порог вхождения из-за его абстракции, иначе не было бы столько обсуждений вокруг него. Ваша ссылка на RSDN это доказывает, но там человек хочет разобраться и грамотный специалист ему объясняет на пальцах. Никто не обсуждает TCP/IP в таких масштабах, потому что протокол, там все понятно. В современном мире, ждать, что когда-то джуны познают эту философию - это что-то из области фантастики. Когда вокруг фреймворки и фреймврками погоняют, когда программируют мышкой, когда никто не знает и не хочет знать, что происходит под капотом метода из библиотеки, которая вызывает другую библиотеку, а та использует третью, мы получаем тонны багованного софта, который никто никогда не будет исправлять и который тратит ресурсы железа. Откуда столько фреймворков? Потому что это попытка (безусловно, успешная) снизить порог вхождения, упростить процесс разработки, повысить скорость разработки. Если человек выбирает фреймворк, он уже практически находится на пути невежества. Лишь единицы понимают, что происходит под капотом какого-нибудь коробочного ORM, а большинство перебирают в цикле строки, будто это какой-то массив в памяти. О какой философии REST может идти речь?

Это может быть сколько угодно неправильно, это может сколько угодно противоречить философии, но это факт и этого не изменить. Я лишь поднимаю этот факт на поверхность и даю несколько рекомендаций, как жить в такой ситуации.

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

Давайте переложим ваш вопрос с лампочкой на JSON-RPC 2.0. Что будет при повторном запросе? Ошибка? Выключение?

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

А вы уверены, что те, кто реализовывал такие кривые методы, которые я приводил в статье, знали про идемпотентность и реализовали это свойство для PUT?

Я вот не уверен. Если они не смогли нормально разложить операции по доменам, есть ли гарантия, что для PUT они сделали как надо? Остается только надеяться, что они про это слышали и не забыли.

Идемпотентность должна быть всегда, в случае с POST в REST-RPC, этого требует сам подход, это неизбежность. При реализации такого подхода разработчик сам столкнется с этой проблемой при первых тестовых прогонах и реализует идемпотентность, если он о ней забыл. Ведь других методов нет.

Спросите любого архитектора - ему, по большому счету, плевать, какие части HTTP протокола его заставят использовать или не использовать. Его задача - управлять сложностью! Он может что-то любить или не любить, но проблем от HTTP он не почувствует. Не стоит себе льстить: HTTP протокол - это не теория струн, он бесконечно проще того, чем архитектор обычно занимается.

Но вот что архитектора действительно волнует - это границы и межкомпонентное взаимодействие. Именно здесь чаще всего рождается лишняя сложность. И если вы предложите разрушить абстракции и аморфно склеить какие-то слои системы, опытный архитектор точно спросит: “Зачем?”. Ведь он знает, что плата высока, и будет безумием добровольно ее заплатить, не получив ничего взамен.

Архитектору плевать, когда люди обсуждают, чему именно они хотят разрешить протечь из транспортного уровня в прикладной уровень (логический уровень взаимодействия систем). И плевать, какой аббревиатуре это будет соответствовать. Важен только сам факт того, что граница нарушена.

Вот вы, например, пытались-пытались вырулить, по крохам собирали участки, где можно уменьшить сложность до удобоваримой. Дописали до раздела обработки ошибок и…

200 OK, на мой взгляд, это как-то очень скучно и сухо… как же промежуточные системы

… и все - транспортный уровень всеми своими кишками протек в приложение. “Скучно ему, видите ли”. Архитектор полностью перепишет эти два слоя, уберёт границу из кода, блокеры из диздока и повысит смету проекта. Какая теперь разница, что именно протекло - можете тащить и все остальное. Урон - нанесен, код - готов, банкет - оплачен.

И проблема с REST именно в этом - вас миллионы. У кого-то протекли коды ошибок, у кого-то глаголы, у кого-то управление кэшами; кто-то тащит родные возможности по управлению идемпотентностью; кто-то боится не быть готовым к мифическим network middleware; кто-то переносит части тела в URL, чтобы найти их в логах; у кого-то протекла аутентификация; кто-то не может работать, если стандартная панель браузера не парсит трафик; кто-то тащит все, для чего есть подсветка синтаксиса в .http файлах; кто-то привык к популярному фреймворку; кто-то не знает свой CDN и готовится ко всему на свете...

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

Как поэтично говорит один из моих знакомых архитекторов: “Если оборона пала, то неважно, что я буду писать в диздок - все равно весь хлеб будет украден, а все девки изнасилованы - это у варваров в крови”.

Спросите, что же делать? Можно ли вообще использовать REST или что-то на него похожее? Конечно, но! Только если это является реальным требованием в техническом задании проекта, с обоснованием в виде твердого намерения использовать те свойства и возможности, которые он предоставляет, и с финансированием последствий. А не мифическое: “а вдруг через 5 лет мы захотим мигать лампочкой в коридоре при неправильном пароле - без изменений в коде”.

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

А когда пользователь у вас регистрируется, вы прям физически его рожаете?
О чем ваш пример с выкрученной лампочкой?

Не уловил суть вопроса. Можете пояснить?

Когда-то написал пару статей про JSON-RPC (https://habr.com/ru/articles/709362/, https://habr.com/ru/articles/710652/)

Не понимаю людей, знающих о JSON-RPC, но продолжающих использовать REST и жаловаться на него. REST неизлечим, там проблемы в идеологии и архитектуре

Весь web 3.0 на JSON-RPC не потому что это хайпово (как раз-таки наоборот), а потому что это удобно

Полностью поддерживаю. Несколько раз сталкивались с JSON-RPC (работали со stratum протоколом и межсервисным велосипедом), остались только самые положительные впечатления.

Кстати, такое забавное наблюдение: JSON-RPC реализованный слабым разработчиком, намного менее проблемный и более приятный в работе, чем RESTful протокол, реализованный моим лучшим разработчиком.

И побочный эффект: если какая-то команда попробовала оба варианта - потом всегда будет напоминать и просить JSON-RPC, даже если ТЗ предполагает что-то другое.

REST неизлечим, там проблемы в идеологии и архитектуре

Было очень интересно почитать коменты к этой статье, как и саму её.
Попал во всё это почти случайно - во время разработки REST API для web-app.

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

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

Спасибо!


То, что с ходу:

  1. REST завязан на транспортный протокол "запрос-ответ", например HTTP (REST вообще сильно прибит к HTTP). На асинхронных протоколах, например websocket он не работает.

  2. Возврат ошибок в REST завязан на коды ошибок транспорта. В результате может быть сложно отличить ошибку транспорта от ошибки приложения. И ошибок приложения может быть гораздо больше, чем стандартных кодов ошибок в протоколе.

  3. REST хорошо ложится на CRUD (Create, Read, Edit, Delete <=> POST, GET, PUT/PATH, DELETE), когда мы работаем с наборами связанных сущностей. Но для многих вещей приходится вводить искусственные сущности. Например, в REST нельзя послать команду "включить лампочку". Мы либо меняем свойство "включено" сущности "лампочка", либо, в более сложных случаях, когда требуется набор связанных действий над несколькими сущностями, вводим новую псевдосущность "включение лампочки" и запрашиваем создание новой такой сущности.

Sign up to leave a comment.

Articles