Несколько лет назад я разрабатывал для одного большого телекома новую информационную систему. Нам приходилось взаимодействовать со всё нарастающим количеством веб-сервисов, открываемых более старыми системами или бизнес-партнёрами. Как вы понимаете, мы получили добрую порцию SOAP-ада. Заумные WSDL, несовместимые библиотеки, странные баги… Где только возможно мы старались продвинуть — и использовать — простые RPC-протоколы: XMLRPC или JSONRPC.


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


  • поддержки разных диалектов (вроде созданных для Apache XMLRPC-расширений),
  • встроенной конверсии между исключениями Python и иерархическими кодами ошибок,
  • раздельной обработки функциональных и технических ошибок,
  • автоматических повторных попыток в случае технических ошибок,
  • релевантного журналирования и сбора статистики до и после запросов,
  • доскональной проверки входных данных…

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


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



Разработчик отдыхает после трудной получасовой интеграции RPC API


А затем появился REST.


REpresentational State Transfer — передача состояния представления.


Эта новая волна сотрясла основы межсервисного взаимодействия.


RPC умер, будущее было за RESTful: ресурсы живут на своих собственных URL, а манипулировать ими можно только по протоколу HTTP.


С тех пор каждый API, который нам приходилось выставлять или к которому мы обращались, превращался в новую трудность, если не сказать — в безумие.


А что за проблема с REST?


Чтобы не описывать на пальцах, проиллюстрирую на примере. Вот маленький API, типы данных убраны для удобства чтения.


createAccount(username, contact_email, password) -> account_id
addSubscription(account_id, subscription_type) -> subscription_id
sendActivationReminderEmail(account_id) -> null
cancelSubscription(subscription_id, reason, immediate=True) -> null
getAccountDetails(account_id) -> {full data tree}

Просто добавьте правильно задокументированную иерархию исключений (InvalidParameterError, MissingParameterError, WorkflowError…) с подклассами для определения важных ситуаций (к примеру, AlreadyExistingUsernameError), и порядок.


В этом API легко разобраться, его легко использовать, он надёжен. Он поддерживается точной машиной состояний (state machine), но ограниченный набор доступных операций удерживает пользователей от необдуманных действий (вроде изменения даты создания аккаунта).


Ожидаемая длительность выставления этого API в качестве простого RPC-сервиса: несколько часов.


Так, а теперь в дело вступает RESTful.


Никаких стандартов, никаких точных спецификаций. Лишь невнятная «философия REST», бесконечные дебаты и множество дурацких костылей.


Как вы сопоставите точные функции из приведённого примера с CRUD-операциями? Является ли отправка напоминающего письма обновлением атрибута must_send_activation_reminder_email? Или созданием activation_reminder_email resource? Разумно ли использовать DELETE для cancelSubscription(), если подписка остаётся живой в течение grace-периода и в любой момент может быть активирована? Как вы распределяете по конечным точкам дерево данных getAccountDetails(), чтобы соответствовать модели данных REST?


Какую URL-endpoint вы присваиваете каждому «ресурсу»? Да, это просто, но приходится делать в любом случае.


Как выражаете разнообразие ошибочных состояний с помощью очень ограниченного набора HTTP-кодов?


Какие форматы сериализации, какие специфические диалекты вы используете для ввода и вывода полезных данных?


Как именно вы распределяете эти простые сигнатуры по HTTP-методам, URL, строкам запросов, полезным данным, заголовкам и кодам статуса?


И вы часами переизобретаете колесо. Причём не заточенное под вас, умное колесо, а сломанное и хрупкое. Оно нарушает спецификации, даже не замечая этого, а чтобы разобраться в колесе, нужно прочитать тома документации.



Как так вышло, что REST требует столько РАБОТЫ?


Это и парадокс, и бесстыжий каламбур (игра слов: rest может означать «отдых»).


Давайте рассмотрим искусственные проблемы, возникшие из этой философии проектирования.


Удовольствие от глагольных REST-команд


REST вам не CRUD, его сторонники будут уверять, что вы не спутаете эти два понятия. А через несколько минут они начнут радоваться, что у глагольных HTTP-команд прекрасно определённая семантика для создания (POST), получения (GET), обновления (PUT/PATCH) и удаления (DELETE) ресурсов.


Сторонники открыто восхищаются, что нескольких HTTP-команд достаточно для выражения любой операции. Конечно, достаточно. Точно так же, как горстки этих команд достаточно для выражения на английском языке любой концепции: «Сегодня обновил своим телом моё АвтомобильноеВодительскоеСиденье и создал ЗажиганиеДвигателя, но ТопливныйБак себя удалил». От того, что вы можете так сделать, результат не становится менее уродливым. Если только вы не обожаете язык токипона.


Если важен минимализм, то хотя бы делайте всё правильно. Вы знаете, почему PUT, PATCH и DELETE никогда не были реализованы в браузерных формах? Потому что они бесполезны и вредны. Нельзя просто использовать GET для чтения и POST для записи. Или выполнять POST эксклюзивно, когда нежелательно кеширование на HTTP-уровне. Остальные глагольные команды в лучшем случае будут вам мешать, а в худшем — просто испортят вам целый день.


Хотите с помощью PUT обновлять свои ресурсы? Ладно, но Пресвятые Спецификации утверждают, что ввод данных должен представлять собой «полный ресурс» (complete resource), т. е. нужно следовать той же схеме, что и у вывода данных с помощью GET. И что вы будете делать с многочисленными параметрами только для чтения, возвращаемыми командой GET (время создания, время последнего обновления, сгенерированный сервером токен…)? Вы пренебрегаете ими и нарушаете принципы PUT? Вы в любом случае их вставляете и ожидаете «конфликта HTTP 409», если они не совпадают с серверными значениями (потом заставляя вас отправлять GET…)? Вы даёте им случайные значения и ожидаете, что сервер будет их игнорировать (удовольствие от тихих ошибок)? Выберите, что вам ближе, REST не даёт ясного понимания, что такое атрибут только для чтения, в ближайшем будущем эта ситуация не изменится. При этом опасность GET в том, что он должен возвращать пароль (или номер банковской карты), который затем отправляется в предыдущий POST/PUT — удачи вам и с этими параметрами только для записи.


Хотите для обновления своего ресурса использовать PATCH? Прекрасно, но, как и 99 % людей, использующих глагольные команды, будете просто отправлять в полезных данных своего запроса подмножество полей ресурса в надежде, что сервер правильно поймёт, что вы хотели сделать (со всеми возможными побочными эффектами). Многие параметры ресурсов глубоко взаимосвязаны или обоюдно эксклюзивны (например, в данных о пользовательском счёте указывается номер банковской карты ИЛИ токен PayPal), но RESTful-архитектура скрывает и эту важную информацию. Но вы в любом случае опять нарушите спецификации: PATCH не должен отправлять кучу полей для переопределения. Он должен отправлять «набор инструкций», которые будут применяться к ресурсам. Так что берите блокнот и кружку с кофе, придётся определиться с выражением этих инструкций и их семантикой. Не-изобретённый-здесь синдром — это стандарт де-факто в мире REST.


Хотите удалять ресурсы с помощью DELETE? Ладно, но надеюсь, вам не понадобится предоставлять важную контекстную информацию типа PDF-скана пользовательского запроса о расторжении. DELETE не должен содержать полезную информацию. Этим ограничением REST-архитекторы часто пренебрегают, потому что большинство веб-серверов не заставляют соблюдать это правило в запросах к себе. Но насколько совместимым будет DELETE-запрос с прикреплённой двухмегабайтной base64-строкой запроса?



Приверженцы REST с лёгкостью заявляют, что «люди всё делают неправильно» и что их API «на самом деле не RESTful». К примеру, многие разработчики используют PUT для создания ресурсов прямо в финальном URL (/myresourcebase/myresourceid), в то время как «правильный способ» — применить POST к родительскому URL (/myresourcebase) и позволить серверу с помощью HTTP-заголовка «расположения» показать URL нового ресурса (это не HTTP-переадресация). Хорошая новость: разницы никакой. Все эти сурьёзные принципы — как споры между сторонниками Big Endian и Little Endian, философы часами переубеждают друг друга, но всё это «правильное делание» имеет очень мало отношения к реальным проблемам.


Кстати… делать URL’ы вручную всегда очень весело. Вы знаете, сколько реализаций правильно применяют urlencode() к идентификаторам при сборке REST URL’ов? Не слишком-то много. Готовьтесь к грубым вторжениям и SSRF/CSRF-атакам.



Когда вы забыли применить urlencode к именам пользователей в одном из 30 своих составленных вручную URL’ов


Удовольствие от REST-обработки ошибок


Почти каждый программист может выполнить «номинальную» работу. Обработка ошибок — одно из свойств, делающих ваш код надёжной программой или огромной кучей хлама.


HTTP из коробки предоставляет список кодов ошибок. Отлично, давайте посмотрим.


Использовать HTTP 404 Not Found для уведомления об отсутствующем ресурсе — звучит чертовски по-RESTful, верно? Паршивое решение: ваш nginx был ошибочно сконфигурирован на один час, так что пользователи вашего API получают только ошибки 404 и вычищают сотни аккаунтов, думая, что они удалены…



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


Кажется, вполне можно выбрать HTTP 401 Unauthorized, если у пользователя нет данных для доступа к стороннему сервису? Однако если Ajax-вызов в браузер Safari получит такой код, то может напугать вашего конечного пользователя очень неожиданным запросом пароля (несколько лет назад так и происходило).


HTTP существовал задолго до появления REST, и в экосистеме веба можно найти множество толкований значений кодов ошибок. Использовать их для передачи ошибок приложения — всё равно что хранить токсичные отходы в молочных бутылках: однажды у вас неизбежно возникнут проблемы.


Некоторые стандартные коды ошибок HTTP характерны для Webdav, другие для Microsoft, а у оставшихся такие расплывчатые описания, что от них никакого толку. В результате, как и большинство пользователей REST, вы, вероятно, для выражения исключений в своём приложении используете случайные HTTP-коды вроде HTTP 418 I’m a teapot или вообще неприсвоенные номера. Или бесстыдно возвращаете HTTP 400 Bad Request на все функциональные ошибки, а затем изобретаете собственный корявый формат ошибок, с булевыми значениями, цифровыми кодами, описательными блоками и преобразованными сообщениями, засунутыми в произвольные полезные данные. Или вы вообще забиваете на корректную обработку ошибок: просто возвращаете сообщение на обычном языке в надежде, что вызывающей стороной будет человек, который сможет проанализировать проблему и принять меры. Удачи вам в общении с такими API из автономных программ.


Удовольствие от концепций REST


REST сделал карьеру на хвастовстве либо концепциями, которые и так уважает любой находящийся в здравом уме архитектор, либо принципами, которым сам REST даже не следует. Вот несколько выдержек с сайтов из первых позиций поисковой выдачи:


REST — это клиент-серверная архитектура. У клиента и сервера разные задачи.


Какая сенсация в мире разработки ПО.


REST предоставляет единый интерфейс для взаимодействия компонентов.


Ну, собственно, как и любой другой протокол, который считается лингва франка в целой экосистеме сервисов.


REST — это система, состоящая из уровней. Отдельные компоненты ограничены тем уровнем, с которым они в данный момент взаимодействуют.


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


REST замечательный, потому что он не отслеживает состояния (stateless).


Быть может, за каким-то веб-сервисом скрывается огромная база данных, но сервис не помнит состояния клиентов. Ну, он помнит сессии аутентификации, разрешения доступа… но всё же он не отслеживает состояния. Точнее, он их не отслеживает в той же мере, что и любой протокол на основе HTTP, вроде того же RPC.



С помощью REST вы можете управлять мощью HTTP-кеширования!


Тут можно сделать как минимум одно заключение: GET-запрос и его заголовки управления кешированием хорошо ладят с веб-кешами. Получается, локальных кешей (Memcached и т. д.) достаточно для 99 % веб-сервисов? Неуправляемые кеши — это опасные чудовища. Кто из вас хочет открывать свои API в чисто текстовом формате, чтобы какой-нибудь Varnish или прокси мог доставлять устаревший контент намного позже обновления или удаления ресурса? Возможно даже, чтобы мог доставлять «вечно» в случае ошибки в конфигурации? Система должна быть безопасной по умолчанию. Я искренне признаю, что некоторые высоконагруженные системы нуждаются в HTTP-кешировании, но гораздо дешевле открывать несколько конечных точек GET для тяжёлых операций только для чтения, а не переводить все операции на REST с его сомнительной обработкой ошибок.


Благодаря этому REST обладает высокой производительностью!


Мы в этом уверены? Любой проектировщик API знает: локально нам нужны мелкие API, чтобы можно было делать что захочется; а удалённо нам нужны крупные API, чтобы уменьшить влияние обменов данными по сети между клиентом и сервером. И здесь REST тоже с треском проваливается. Распределение данных по «ресурсам», каждый экземпляр на своей собственной конечной точке, приводит к проблеме N + 1 запросов. Чтобы получить все пользовательские данные (аккаунт, подписки, информация о счёте…) — вам придётся сделать N + 1 HTTP-запросов. И вы не сможете их распараллелить, потому что не знаете заранее уникальные ID связанных ресурсов. Это, а также невозможность извлечь только часть объектов ресурса, превращается в самое настоящее узкое место.


У REST лучше совместимость.


Это как? Почему тогда так много REST веб-сервисов содержат в своих базовых URL’ах “/v2/” или “/v3/”? C помощью высокоуровневых языков не так уж трудно реализовать API, совместимые вперёд и назад, пока вы следуете простым правилам при добавлении/избегании параметров. Насколько я знаю, REST не привносит сюда ничего нового.


REST прост, все знают HTTP!


Ну, все знают и про валуны, только люди предпочитают строить дома из более удобных материалов. Точно так же XML — метаязык, к HTTP — метапротокол. Чтобы получить настоящий протокол уровня приложения (чем являются «диалекты» по отношению к XML), вам придётся очень много всего определить. И в результате вы получите Ещё Один Протокол RPC, как будто мало уже имеющихся.


REST так прост, по нему можно из оболочки делать запросы с помощью CURL!


На самом деле с помощью CURL можно обращаться по любому протоколу на основе HTTP. Даже по SOAP. Нет ничего сложного в отправке GET-команд, но желаю вам удачи в написании вручную JSON- или XML-полезных данных в POST-командах. Обычно люди используют вспомогательные файлы или, что гораздо удобнее, эффективные API-клиенты, инстанцируемые прямо в командной строке интерфейсов разных языков программирования.


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


Моя любимая цитата. Я встречал её множество раз, в разных формулировках, зачастую в сочетании с модным выражением HATEOAS; иногда после неё ставят осторожные (но бесполезные) фразы об «исключениях». Я не знаю, в каком мире фантазий живут эти люди, но в нашем мире клиентская программа — это не муравейник. Она не обращается случайным образом к удалённым API, решая потом, как лучше всего их обработать: с помощью шаблонов распознавания или чёрной магии. У клиента есть конкретные ожидания: с помощью PUT передать это поле с этим значением вон тому URL’у, а и серверу лучше уважать семантику, согласованную при интеграции, иначе может начаться ад.



Когда спрашиваешь, как же работает HATEOAS


Как делать REST правильно и быстро?


Забудьте о «правильно». REST — это как религия, ни один смертный не сможет постичь всех высот его гениальности и «сделать правильно».


Правильный вопрос: если вам приходится открывать веб-сервисы в RESTful-стиле или работать с ними, как можно поскорее закончить с этим и перейти к более конструктивным задачам?


Как индустриализировать выставление серверной части?


У каждого веб-фреймворка свой способ определения URL-конечных точек. Так что если нужно воткнуть в ваш любимый сервер имеющийся API в качестве REST-конечной точки, то готовьтесь к большим зависимостям или к доброй порции шаблонного кода, который придётся писать вручную.


Библиотеки вроде Django-Rest-Framework автоматизируют создание REST API, действуя по принципу ориентированных на обработку данных обёрток вокруг SQL/noSQL-схем. Если вам просто нужен «CRUD поверх HTTP», то проблем с ними не будет. Но если вам нужно выставлять настоящие API с рабочими процессами, ограничениями и всем прочим, то придётся долго обрабатывать любой REST-фреймворк напильником, чтобы подогнать под свои нужды.


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


Как индустриализировать клиентскую интеграцию?


По моему опыту, никак.


Придётся читать длинную документацию для каждой интеграции API и следовать подробным инструкциям выполнения каждой из N возможных операций.
Придётся вручную собирать URL’ы, писать сериализаторы и десериализаторы, а также изучать, как закостылить неясности API. Укрощать чудовище будете методом проб и ошибок.
Вы знаете, как поставщики веб-сервисов компенсируют это и облегчают внедрение?


Они просто пишут собственные официальные реализации клиентов.


ДЛЯ. КАЖДОГО. ОСНОВНОГО. ЯЗЫКА. И. ПЛАТФОРМЫ.


Я недавно работал с системой управления подписками. Авторы предоставляют клиентские части для PHP, Ruby, Python, .NET, iOS, Android, Java… и ещё несколько внешних разработок для Go и NodeJS.


Каждый клиент живёт в собственном Github-репозитории. У каждого собственные длинные списки коммитов, отчётов о багах и pull-реквестах. Каждый со своими примерами использования. У каждого своя вычурная архитектура, что-то среднее между ActiveRecord и RPC-прокси.


Это поразительно. Сколько времени потрачено на эти странные обёртки вместо улучшения нормальных, ценных, эффективных веб-сервисов.



Сизиф разрабатывает Ещё Один Клиент для своего API


Заключение


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


А с REST всё превратилось в безумие: сопоставляем яблоки с апельсинами, восхваляем HTTP-спецификации, чтобы через минуту их лихо нарушить.


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


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


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


Почти прозрачные RPC удовлетворяли 99 % людей, а имеющиеся протоколы, пусть и несовершенные, прекрасно работали. А этот массовый монопсихоз, связанный с наименьшим общим знаменателем веба — HTTP, — в основном привёл к огромным потерям времени и серого вещества.


REST обещал простоту, а принёс сложность.
REST обещал надёжность, а принёс хрупкость.
REST обещал совместимость, а принёс неоднородность.
REST — это новый SOAP.


Эпилог


Будущее может быть светлым. Есть множество превосходных протоколов, бинарных и текстовых, со схемами и без, некоторые используют новые возможности HTTP2… так давайте двигаться дальше. Нельзя вечно оставаться в каменном веке веб-сервисов.


Многие спрашивают меня об этих протоколах, эта тема заслуживает отдельной истории. Но вы можете обратить внимание на XMLRPC и JSONRPC, или на характерные для конкретных языков слои вроде Pyro или RMI для внутреннего использования, или на новичков вроде GraphQL и gRPC для публичных API…

Комментарии (143)


  1. Zverik
    21.12.2017 15:24
    +2

    Прочитал — и пошёл в исходную статью, проверить дату. Пока все топят за переход с REST на GraphQL, автор узнал, что кроме SOAP бывает ещё и REST.


    1. symbix
      21.12.2017 15:38

      REST и "то, что люди делают, называя REST" — это две большие разницы. :) Если люди будут понимать graphql так же, как сейчас понимают REST, мне уже заранее страшно.


    1. k12th
      21.12.2017 15:47

      для одного большого телекома

      энтерпрайз же


    1. AstarothAst
      21.12.2017 15:55
      +1

      GraphQL не менее замороченная фигня, которая сулит ровно ту же боль, только с иного ракурса.


  1. OlegYch_real
    21.12.2017 15:44

    REST(ful) — это то что случается когда язык созданный для того чтобы обезьянка танцевала становится индустриальным стандартом


  1. MOTORIST
    21.12.2017 16:07

    Критиковать каждый может. Если у меня клиент — браузер, то либо REST Api, либо GraphQL (в связке с apollo). Выбор не велик.

    Код для Angular из apollo:

    const CurrentUserForProfile = gql`
      query CurrentUserForProfile {
        currentUser {
          login
          avatar_url
        }
      }
    `;
    



    1. lair
      21.12.2017 16:11

      Если у меня клиент — браузер, то либо REST Api, либо GraphQL

      А почему? Что мешает использовать любой велосипедный протокол поверх HTTP?


      1. sshikov
        21.12.2017 21:38

        Чтобы никто другой уж точно не смог воспользоваться? :)


        1. lair
          22.12.2017 00:14

          А надо?


    1. ArVaganov
      21.12.2017 19:21

      А на стороне сервера?


  1. igrishaev
    21.12.2017 16:23

    Достаточно JSON-RPC.


    1. rraderio
      21.12.2017 18:03
      +2

      Или JSON API jsonapi.org


  1. ffriend
    21.12.2017 16:52

    Не прочувствовал проблемы.


    Никаких стандартов, никаких точных спецификаций.

    HTTP — стандарт, хорошо задукоментированный. Пути, как правильно, достаточно понятны. Хочется большей точности — пишите документацию, тут никак не отвертишься, ни в случае с REST, ни в случае с чем-то ещё — ни SOAP, ни GraphQL не покроют всех деталей.


    Какую URL-endpoint вы присваиваете каждому «ресурсу»? Да, это просто, но приходится делать в любом случае. [...] Как вы сопоставите точные функции из приведённого примера с CRUD-операциями?

    Здесь автор предполагает, что API просто оборачивает какую-то БД, где есть какие-то таблицы-ресурсы. Но API может делать много чего другого — запускать процессы на кластере, делать вычисления, обращаться к другим API и т.д. Какой протокол покроет это? XML-схема здесь чем-нибудь поможет?


    Паршивое решение: ваш nginx был ошибочно сконфигурирован на один час, так что пользователи вашего API получают только ошибки 404 и вычищают сотни аккаунтов, думая, что они удалены…

    Откройте для себя www.pingdom.com иди десятки подобных ресурсов. Сайт может упасть по десяткам причин, с таким же успехом можно делать быстрые правки по SSH прямо на сервере и не проверять результат.


    Хотите с помощью PUT обновлять свои ресурсы? [...] Хотите для обновления своего ресурса использовать PATCH? [...] Хотите удалять ресурсы с помощью DELETE?

    Ок, если такие проблемы, используйте везде POST. Не по стандарту? Да, наверное, и что? Покрыть стандартом 100% случаев невозможно, но вас никто и не заставляет в точности следовать стандарту. REST вполне неплохо описывает то, что от вас будут ожидать пользователи, например, что GET не будет менять состояние, что DELETE удалит объект и т.п., но если в некоторых случаях такое поведение невозможно, пометьте эту часть в документации жирным.


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


    1. ffriend
      21.12.2017 22:40

      Товарищи, которые минусуют, вы хоть комментарии какие-нибудь оставьте. А то видно, что вы не согласны, но с чем и почему, остаётся только догадываться :)


      1. fogone
        21.12.2017 23:18

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


        1. ffriend
          22.12.2017 00:25

          Эээ, так а о чём тогда статья?


          Я, в основном, реагировал на конкретные фразы в статье, которые у меня вызвали недоумение и ощущение "запугивания" читателя. Ну вот, например:


          Использовать HTTP 404 Not Found для уведомления об отсутствующем ресурсе — звучит чертовски по-RESTful, верно? Паршивое решение: ваш nginx был ошибочно сконфигурирован на один час, так что пользователи вашего API получают только ошибки 404 и вычищают сотни аккаунтов, думая, что они удалены…

          Речь, судя по всему, идёт про внешние ресурсы а-ля интернет-магазинов, т.е. не про внутренние сервисы, которые общаются автоматически. Соответственно, девопс или админ продеплоил конфигурацию nginx, не проверил, работает ли оно, на сервере не был настроен алертинг и никакие внешние сервисы типа pingdom? Ну ок, не очень ответственный человек, но поверим. Но, если пользователи не могут войти в свой аккаунт, то как они "вычищают" их? Т.е. вся ситуация выглядит притянутой за уши.


          Ну или вот:


          В результате, как и большинство пользователей REST, вы, вероятно, для выражения исключений в своём приложении используете случайные HTTP-коды вроде HTTP 418 I’m a teapot или вообще неприсвоенные номера. [...] Удачи вам в общении с такими API из автономных программ.

          За последние 3-4 года я написал штук 20 REST-сервисов, и ни в одном не использовал "левые" коды, как раз потому что к моим сервисам обращались автономные программы, которые по коду понимали, что делать дальше — подождать (503), запросить авторизацию (401 / 403), создать тикет (500) или нормально обработать результат (200). Люди, с которым я работал, тоже никогда так не делали. Публичные API, с которыми приходилось работать, тоже использовали коды по назначению. Тем не менее, автор делает необоснованные предположения, либо чтобы усилить свой аргумент, либо потому что привык к другой среде, о чём я и написал в заключении.


          Я писал сервисы, которые общались друг с другом по SOAP, REST, Websockets (включая подпротоколы), голому TCP, AMQP, NATS, Kafka и т.д., поэтому, наверное, я всё-таки немного в теме. И даже если допустить, что статью целиком я не понял, отдельные фразы вроде указанных выше интерпретировать иначе чертовски сложно.


          1. VolCh
            22.12.2017 11:14

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

            Все locations работают, кроме одного. Но самого важного для пользователей.


            Как раз потому что к моим сервисам обращались автономные программы, которые по коду понимали, что делать дальше — подождать (503), запросить авторизацию (401 / 403), создать тикет (500) или нормально обработать результат (200)

            А как они обрабатывали стандартные и полустандартные коды? Хотя бы 201, 204, 409, 422? Как обрабатывали 302 — постандарту или как браузеры?


            1. ffriend
              22.12.2017 12:14

              Все locations работают, кроме одного. Но самого важного для пользователей

              Опять же, речь ведь идёт про внешний сервис, с UI, пользователями и всем таким? Значит пользователь не знает ни про какие locations, ему нужно войти в свой аккаунт, найти кнопку "delete my account" и нажать на неё. Но войти он не может, потому что 404.


              Автоматические программы могли бы знать про locations, но если такая программа делает DELETE /myobject после того как GET /myobject вернул 404 — это тоже, мягко говоря, странное поведение.


              А как они обрабатывали стандартные и полустандартные коды? Хотя бы 201, 204, 409, 422? Как обрабатывали 302 — постандарту или как браузеры?

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


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


              1. VolCh
                22.12.2017 14:06

                делает DELETE /myobject после того как GET /myobject вернул 404 — это тоже, мягко говоря, странное поведение.

                Делает DELETE /user/:id после того как GET /user/:id/some-important возвращает 404


                1. ffriend
                  22.12.2017 15:04

                  Так вы пример такой ситуации-то приведите.


                  1. VolCh
                    22.12.2017 15:27
                    -1

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


                    1. ffriend
                      22.12.2017 15:47

                      Нажали ссылку где? В письме GET запросом по URL без аутентификации в аккаунт?


                      За свою жизнь я не видел ни одного ресурса, где аккаунт можно было бы удалить просто нажав кнопку. Обычно для этого нужно войти в свой аккаунт и в "опасной зоне" своего профиля нажать красную кнопку, а затем ещё и подтвердить паролем. И даже после этого аккаунт обычно помечается как "удалённый", но у пользователя есть N дней, чтобы отменить действие.


                      И это не говоря уже о том, что игра могла не работать из-за десятка других причин — проблем сети, неудачного деплоя, бага, перегрузки сервера и т.д. И есть десяток способов защититься от этого — алертинг, автоматическое и ручное тестирование, мониторинг внешними инструментами. Но виноват, конечно, REST.


                      1. VolCh
                        22.12.2017 15:52

                        Аутентификация, как я понимаю, была по одноразовому токену, по GET перешёл в настройки профиля, на страниц подписки, но выбрал удаление аккауунта.


                        Я вам привожу пример, как из-за ошибок на стороне сервера пользователь уходит с ресурса навсегда.


                        1. lair
                          22.12.2017 15:56

                          А пример нужно той ситуации, где 404, возвращенный прокси-сервером, приводит к некорректному поведению клиентского приложения.


                          1. VolCh
                            22.12.2017 16:09

                            так что пользователи вашего API получают только ошибки 404 и вычищают сотни аккаунтов, думая, что они удалены…

                            По-моему, тут речь непосредственно о том, что думают пользователя, получая 404.


                            1. lair
                              22.12.2017 16:12

                              Нет.


                              so your API consumers got only 404 errors and purged hundreds of accounts, thinking they were deleted

                              API consumer — это не пользователь, это потребитель API (программа). А purge — это не (совсем) удаление.


                              1. VolCh
                                22.12.2017 16:29

                                Значит зря время потратил из-за неудачного перевода :(


                                1. mayorovp
                                  22.12.2017 16:31

                                  Да все в порядке с переводом! Пост-то про API, а значит если написано «пользователь» — подразумевается «программа-пользователь» или «система-пользователь».


                                  1. VolCh
                                    22.12.2017 16:34

                                    "клиент" или "потребитель" обычно употребляется в контексте API, а "пользователь" — разработчик


                          1. MacIn
                            22.12.2017 22:18

                            Имеется в виду удаление связанных аккаунтов на другом сервисе-потребителе, или я что-то не понял?


                            1. lair
                              23.12.2017 10:45

                              Мне тоже так показалось.


                        1. oxidmod
                          22.12.2017 16:07

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


          1. fogone
            22.12.2017 20:24

            Но, если пользователи не могут войти в свой аккаунт, то как они «вычищают» их? Т.е. вся ситуация выглядит притянутой за уши.

            Этот пример просто показывает, что смешение транспортного уровня и уровня логики приводит к такого рода ошибкам. А вычистить из за такой ошибки пользователей вообще ничего не стоит, потому что где-то на другом серваке стоит другой сервис, который синхронизирует пользователей себе локально, для чего обращается к нашему и если видит, что его уже нет, то удаляет и у себя, например. Это взятый из головы пример, но в целом вероятный. Суть проблемы в том, что вызывающий скприт не понял, что тот 404 который пришел, он совсем не про то.
            как раз потому что к моим сервисам обращались автономные программы, которые по коду понимали, что делать дальше

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

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

            В заключении вы говорите о том, что автор привык к soap, хотя автор недвусмысленно намекает, что проще было бы место soap-а и rest-а использовать какие-то простые http-rpc. Что наводит меня на мысль, что вы или не знаете, что имеет ввиду автор или просто не читали, но осуждаете.
            И даже если допустить, что статью целиком я не понял, отдельные фразы вроде указанных выше интерпретировать иначе чертовски сложно.

            Но возможно местами, если всё же вникнуть в написанное.


            1. ffriend
              22.12.2017 23:17

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

              Так он удаляет у себя, а не на нашем сервере. К тому же, если он удаляет пользователя локально, значит для него это что-то вроде кеша и он может потом ещё раз сделать GET и всё восстановить.


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


              Какой http-код вы возвращаете если вам нужно сказать клиенту, что транзакция длилась слишком долго и была отменена? [...] Всё верно, проблема только, что на все случаи кодов нет и особенно для более сложных api всё равно приходится что-то придумывать сверх того, что есть.

              Лично я бы использовал 422 (unprocessable entity), но если сомневаетесь, возвращайте 400 (bad request) и пояснение. Расспространённое заблуждение, что HTTP коды должны описывать все возможные ситуации и ошибки, но по сути это классы ошибок, а внутри ответа уже может быть указана точная причина. Это ничем не отличается, например, от классов исключительных ситуаций (скажем, OSError или LookupError в Python), которые покрывают сразу массу возможных причин, а точная проблема диагностируется по полям эксепшена.


              В заключении вы говорите о том, что автор привык к soap

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


              Но есть масса других доменов, где требования совершенно другие. От GitHub API мне не нужны все 250 эндпойнтов, я хочу просто доставать количество звёзд проекта. От StackOverflow мне не нужен полноценный клиент, мне достаточно уметь считывать текст вопроса и теги. С другой стороны, мне это надо делать из разных языков, в т.ч. тех, для которых нет *RPC клиента. И если я смогу для своего запроса использовать обычный, доступный везде HTTP с уже знакомой семантикой (знакомые "глаголы", коды, с которыми я уже работал и т.д.), то это, как ни крути, большой плюс.


              1. MacIn
                24.12.2017 04:03

                Так он удаляет у себя, а не на нашем сервере. К тому же, если он удаляет пользователя локально, значит для него это что-то вроде кеша и он может потом ещё раз сделать GET и всё восстановить.

                Вообще не факт. Допустим, он хранит у себя какую-то информацию, пивязанную к пользователю, например, список его покупок, или сообщений на втором ресурсе, или каких угодно других обрывков информации. И это будет удалено. Откуда восстановится эта информация? (В общем случае, не рассчитывая на резервное копирование или удаление через отметку).


  1. oxidmod
    21.12.2017 17:02

    Хотите с помощью PUT обновлять свои ресурсы? Ладно, но Пресвятые Спецификации утверждают, что ввод данных должен представлять собой «полный ресурс» (complete resource), т. е. нужно следовать той же схеме, что и у вывода данных с помощью GET.


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


    1. mayorovp
      22.12.2017 08:47

      Проблема в том, что это нарушает семантику PUT.


      1. oxidmod
        22.12.2017 10:33

        REST не привязан к HTTP. Вы хоть почтовыми голубями REST можете сделать. Главное чтобы ресурсы имели уникальные идентификаторы и запросы содержали все необходимое для выполнения этого самого запроса.


      1. VolCh
        22.12.2017 11:17

        Нарушает семантику PUT в HTTP как в прикладном протоколе. Если мы его используем как транспортный (а де-факто почти всегда так бывает в "REST API"), то пофиг на семантику :)


        1. mayorovp
          22.12.2017 11:30

          … до тех пор пока посередине не окажется особо хитрый прокси-сервер.


          1. VolCh
            22.12.2017 11:59

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


      1. uniqm
        22.12.2017 13:34

        Семантику PUT нарушает, так как надо использовать метод PATCH.


        1. mayorovp
          22.12.2017 15:13

          В статье то же самое написано. Но там дальше про недостатки PATCH тоже есть…


  1. Loki3000
    21.12.2017 17:04
    +2

    А кто-то может простыми словами объяснить чем плох RPC? Ну и, соответственно, лишен ли REST этих недостатков?


    1. rraderio
      21.12.2017 18:15

      Кэширование


      1. izzholtik
        21.12.2017 19:46

        А что с ним?


        1. kuftachev
          21.12.2017 20:12
          +4

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


          1. vvzvlad
            22.12.2017 19:36

            Просили «простыми словами», а не «правильными»


    1. kuftachev
      21.12.2017 20:27

      Если под RPC иметь ввиду SOAP, то его ругают за то, что аналог с REST будет легче весить (сам запрос и ответ).
      А если говорить о настоящем RPC, особенно для общения между однотипными системами типа RMI у Java, то он просто не нужен для того говнокода, который сейчас пишут.


    1. vedenin1980
      21.12.2017 20:58
      +2

      чем плох RPC? Ну и, соответственно, лишен ли REST этих недостатков?

      RPC в Java не совместим с RPC в С# и т.д. REST всего лишь оказался стандартом, который поддерживают так или иначе все, соответственно нет если есть несколько микросервисов Java на REST, вы можете переписать одни из них на GO и все остальные этого не заметят. В RPC вы жестко привязаны к языку (и даже хуже иногда к конкретной версии языка, скажем, при передачи классов от Java 8 к Java 6 могут быть проблемы).

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


      1. VolCh
        21.12.2017 21:32

        REST всего лишь оказался стандартом

        REST — не стандарт, а архитектурные принципы построения распределённых систем. Принципы REST широко использовались для создания протокола самой популярной, наверное, из них, веба. Протокол этот известен как HTTP. Но REST может быть реализован без HTTP, либо используя его как транспорт.


        1. vedenin1980
          21.12.2017 21:40
          +1

          REST — не стандарт, а архитектурные принципы построения распределённых систем.

          Вы же понимаете, что это по сути одно и тоже? Ну да, формально, никто не мешает отправлять письма по почте и называть это REST, но у построения RESTfull сервисов есть вполне определенные правила и c вашим сервисом не смогут работать, если вы не будите им следовать. Де-юре, не стандарт, де-факто — вполне, стандарт.

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

          Так наоборот же, сначала был веб/HTTP, а потом REST. Тут уж скорее REST был создан по подобию HTTP, а никак не наоборот (хотя они вообще-то о разном).

          Но REST может быть реализован без HTTP, либо используя его как транспорт.

          Спасибо, кэп. По-моему, тут всем прекрасно известно, что такое REST. Только к чем это?


          1. VolCh
            21.12.2017 22:25

            Вы же понимаете, что это по сути одно и тоже?

            Я понимаю, что чаще всего когда говорят о REST, то имеют ввиду попытки натянуть предметную область на семантику HTTP. Или наоборот. И говорят так, чаще всего, по незнанию, свято веря, что DELETE /api/v3/users/1/password это не просто REST, а единственная его правильная реализация.


      1. sshikov
        21.12.2017 21:55
        +1

        RPC в Java не совместим с RPC в С# и т.д.

        Вообще-то RPC — это remote procedure call. Какая такая Java 6 или 8, о чем вы? Это не Java ни разу. Более того, такого стандарта вообще нет, есть SOAP и как его вариация — сообщения SOAP для вызова процедур/методов, с указанием метода и параметров, и возвратом результата (не путать например с Document стилем, когда вы просто посылаете XML, не вызываете непосредственно никакой метод, не передаете параметры, и в общем случае не ждете результата — потому что ваше сообщение могут просто переслать куда-то еще, без ответа). Т.е. SOAP — это не RPC, в общем случае.


        И они вполне себе совместимы между разными языками, если не пытаться передавать внутри сериализованные Java объекты, и не надеяться, что C# их успешно прочитает.


        1. vedenin1980
          21.12.2017 22:05
          +1

          Вообще-то RPC — это remote procedure call. Какая такая Java 6 или 8, о чем вы? Это не Java ни разу. Более того, такого стандарта вообще нет,

          Да, это не стандарт. Это набор разных стандартов под общим именем, например Java RMI.

          есть SOAP и как его вариация — сообщения SOAP для вызова процедур/методов… Т.е. SOAP — это не RPC, в общем случае.

          Так вы уж определитесь RPC это или не RPC.

          И они вполне себе совместимы между разными языками, если не пытаться передавать внутри сериализованные Java объекты, и не надеяться, что C# их успешно прочитает.

          Кто они-то? SOUP, вы сами сказали не RPC, тогда кто с кем совместим? Есть Java RMI — не совместим не с чем кроме Java, есть DCOM — чисто для Microsoft систем, есть куча других RPC протоколов, которые тоже со своими ограничениями и если вы придумаете язык НЯ, естественно там они работать не будут пока кто-то не напишет их реализацию, а REST работает повсеместно (и реализация его при умении работать с сетью в принципе дело простое). Более того язык НЯ может вообще не содержать всех тех сущностей, что хочет какой-нибудь SOUP (ну скажем мы придумали язык без классов и функций, аля SQL), как он будет работать с RPC?


          1. sshikov
            21.12.2017 22:18
            +1

            Если бы вы почитали, что такое SOAP, если бы вы это сделали, вы бы знали, что RPC — это его частный случай. Да, SOAP это не RPC, это намного больше. Но вариант "просто RPC" он вполне себе умеет, и более чем совместимо между разными языками.


            1. vedenin1980
              21.12.2017 22:31

              что RPC — это его частный случай.

              Так все наоборот, SOUP можно назвать одним из RPC протоколов. Одним, скажем, Java Remote Method Invocation это тоже RPC протокол и он не будет совместим ни с чем другим.

              SOAP это не RPC, это намного больше.

              SOUP в статье рассмотрен отдельно. Речь шла о RPC, кроме SOUP.

              Если бы вы почитали, что такое SOAP, если бы вы это сделали, вы бы знали

              Думаю, мне хватит, что я десяток лет SOAP сервисы писал.

              Но вариант «просто RPC» он вполне себе умеет, и более чем совместимо между разными языками.

              Любыми языками? Сможете написать обмен между Brainfuck и С#? Ну или между ассемблером и PL-SQL? Даже чисто теоретически.


              1. justboris
                21.12.2017 22:57

                А почему вы так последовательно пишете SOUP, когда все остальные пишут SOAP?


                1. vedenin1980
                  21.12.2017 23:11

                  тьфу, дурацкий жаргон c работы прицепился. :) Cуп, он суп и есть. :)


                  1. iPumbaza
                    22.12.2017 17:46

                    Но как ни странно — это мыло :)


              1. mayorovp
                22.12.2017 08:50

                Думаю, мне хватит, что я десяток лет SOAP сервисы писал.

                В том-то и дело, что SOAP — это не только веб-сервисы...


              1. sshikov
                23.12.2017 16:05

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


                Есть Java RMI — не совместим не с чем кроме Java,

                А ничего, что я еще лет 10 назад успешно вызывал RMI из C#?


                есть DCOM — чисто для Microsoft систем

                А ничего, что DCOM и COM успешно доступны из Java? И опять же — я это лично делал, и достаточно давно уже. Причем и то, и другое легко гуглятся, ежели вдруг нужно.


                Ваша квалификация в данном вопросе — она видна невооруженным глазом.


                1. VolCh
                  24.12.2017 17:21

                  Просто ради интереса: можно ли из Java-софта, работающего под LInux использовать DCOM-компоненты, работающие на удаленном сервере под Windows, не настраивая ничего особо на стороен последнего и не реализуя самостоятельно весь DCOM проткол на Java? А если можно, то кто предоставляет адаптеры — MS, Oracle или третьи лица?


                1. vedenin1980
                  24.12.2017 23:18

                  А ничего, что я еще лет 10 назад успешно вызывал RMI из C#?

                  А вот тут подробнее, да существует RMI в .Net, но речь шла о Java RMI (в котором использует в том числе Java сериализация объектов). Вы реально соединяли C# с Java через Java RMI? А как Java сериализация объектов работала в C#? Дайте, плиз, ссылки на используемые библиотеки, так как ничего не нагугливается. Реально интересно.

                  DCOM и COM успешно доступны из Java

                  Успешны доступны из Java, запущенной на Linux или FreeBSD? А дайте ссылку на библиотеку, мне очень интересно (без сарказма). Java, запущенная в Windows, конечно, может через C++ библиотеку без проблем обратиться в любому API ОС, а вот как это сделать кросплатформено.


      1. kuftachev
        22.12.2017 10:57

        Мне кажется, Вы просто не понимаете разницу между бинарным и тестовым форматом.


    1. napa3um
      22.12.2017 11:02

      Если оформлять передачу изменений в системе через HTTP-глаголы, выразив это состояние в терминах REST-ресурсов, то у вас уже будет концептуальный каркас для внедрения в свою архитектуру системы кеширования и обработки ошибок (причём это получится красиво в отдельные слои выделить, в которых «смысл» кешируемых ресурсов и ошибок будет выражаться лишь набором параметров инвалидации и человекопонятных описаний ошибок). Всё это можно сделать и без REST-а, но вылизывая свою архитектуру и устраняя из неё противоречия вы сами рано или поздно придёте к семантическому аналогу REST-а. REST — это как бы не набор инструментов, а, скорее, учебник по истории решения типовых проблем в проектировании распределённых приложений. Ценность не в побайтовом следовании спецификации (хотя и будет удобным воспользоваться уже готовыми механизмами HTTP, поддерживаемыми промежуточной инфраструктурой провайдера типа проксей и CDN), а в общем понимании архитектурных принципов, позволяющим реже заходить в тупики противоречий при проектировании.

      Если вам достаточно RPC и непонятны плюсы REST, не переживайте, пользуйтесь тем, что понимаете. REST, по сути, становится остро актуальным лишь в больших проектах (распределённых и по серверам, и по командам разработчиков всех подсистем), а в малых проектах с командой на 1-3 программиста вы можете даже и не столкнуться со всеми теми ужасами согласования, которые решает REST.


    1. idoroshenko
      22.12.2017 16:18

      Если простыми словами, то, тут есть два основных момента, и один второстепенный, где REST должен отличатся в лучшую сторону.

      1. REST является platform agnostic способом общения, который требует от платформы только поддержки HTTP. На одном конце может быть С++ сервис, а на другом Javascript, если они оба могут в HTTP, значит у них уже из коробки общая система управления кэшированием, редиректов, повторных запросов, ошибок, аутентификации и прочих вещей которые уже включает себя HTTP.

      2. Инфраструктура. Между сервисами общающимися с помощью HTTP/REST, может быть легко построено любое количество инфраструктуры отвечающей за балансировку, проксирование, кэширование, безопасность, логирование, редиректы, нетворкинг и многое другое, без каких либо изменений в коде сервиса. Так как почти все инфраструктурные сервисы/тулзы поддерживают HTTP, a REST по своей природе опирается на все возможности HTTP, а не просто использует его как транспорт.

      3. HATEOAS

      PS: я не сторонник REST. Но, если мне нужно будет работать с legacy инфраструктурой, я предпочту REST.


      1. Loki3000
        22.12.2017 16:29

        А RPC разве не может работать через HTTP? Как-то все их постоянно противопоставляют…


        1. mayorovp
          22.12.2017 16:35

          RPC работая через HTTP не оставляет никаких подсказок промежуточным серверам относительно возможностей того же кеширования. Как правило вся семантика ограничивается операцией POST в которой по умолчанию кеширование ответов запрещено.

          Поэтому считается что в случае идеального REST правильно настроить кеши проще.


      1. VolCh
        22.12.2017 16:32

        1 и 2 по сути применимы к чему угодно, использующему HTTP как транспорт.


        1. idoroshenko
          22.12.2017 17:13

          Обычно, чтобы понять назначение RPC запроса, нужно научит ифоаструктуру хотя бы на базовом уровне понимать тело этих запросов. Возьмём самое простое — кэширование. В http/rest у идемпотентных запросов есть явные характеристики, и большенство из них можно смело кэшировать. У RPC запросов, не ясно, есть ли у метода side effects и является ли он безопасным для кэширования. В этой ветке хорошо заметили — RPC почти не оставляет на уровне HTTP подсказок о себе, для него, это всего лишь транспорт.


          1. VolCh
            22.12.2017 17:46

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


  1. Qulac
    21.12.2017 17:15
    -1

    Хабр в помойку скатился.


  1. rraderio
    21.12.2017 17:24

    или на новичков вроде GraphQL и gRPC для публичных API…
    Только для публичных API?


  1. zenkz
    21.12.2017 17:40
    +1

    Мне вот интересно зачем современные программисты усложняют себе жизнь всякими концепциями вроде GraphQL или REST. Основная задача программистов сделать быструю, качественную и легко поддерживаемую и расширяемую систему. Очевидно что REST за пределами CRUD не может с этим справиться, хотя бы потому, что на каждый чих нужно добавлять новый url, в котором часто используется только один вызов (чаще всего GET или POST) — в результате получается тот-же RPC, но под соусом модного RESTа и с кучей проблем. GraphQL неоправдано сложен и на мой взгляд недостаточно безопасен. Он как швейцарский нож — вроде можно сделать много вещей, но если ты делаешь это часто, то лучше иметь отдельный нож, пилу и ножницы. Хотя для прототипирования очень даже неплох… SOAP сильно бюрократизирован и тяжёл. Иногда его можно применять — например для межсистемного взаимодействия или когда можно описать wsdl-ку и предоставить её другой компании для интеграции. Но если честно, то все преимущества SOAP можно реализовать и на REST. При всей своей непопулярности сейчас RPC, а именно json-RPC является идеальным решением. Для себя часто применяю комбинацию REST и JSON-RPC, где REST использую для CRUD операций, а для всего остального — JSON-RPC.


    1. rraderio
      21.12.2017 17:47

      Как вы решаете проблему отдачи данных для разных платформ? для мобильников нужны одни данные, для веба нужны другии.


      1. zenkz
        21.12.2017 18:00

        Способов много, можно добавить ещё один REST сервис (для CRUD). Можно выставить новый сервис (т.е. метод/процедуру), можно добавить параметр в существующий сервис. Можно определять по полям в заголовке запроса от кого пришёл запрос (наверно самый правильный вариант).


        1. rraderio
          21.12.2017 18:09

          И делать/поддерживать документацию для каждой платформы?


          1. zenkz
            21.12.2017 18:52

            Нет, зачем для каждой платформы. Только для сервисов (т.е. что это за сервис и какие параметры принимает и что в результате выдаёт). Чаще всего достаточно добавить /// комментарий к методу и сгенерировать потом документ на их основе.
            А вообще — это частный случай (разных выдач для мобилок и десктопов обычно не так много). Иногда можно отдать избыточную информацию для мобилки. Иногда можно переписать сервис, чтобы потом десктоп дозабрал недостающие данные. Можно применить что-то вроде OData или GraphQL (но не ко всей системе, а только для этого сервиса).


            1. rraderio
              22.12.2017 10:40

              Нет, зачем для каждой платформы.
              Потому что для разных платформ возвращаются разные данные + Клиент может сгенерировать код по документации


  1. robert_ayrapetyan
    21.12.2017 18:17
    +1

    SOAP, REST… Послушайте реальную историю двух-недельной давности, которая со мной приключилась.

    Новый супер-важный клиент (НСВК):… ну и вот примеры запросов ответов которые вы должны нам слать (приаттачивает какие-то непонятные файлы со строками, похожими на команды модема)
    Я: че это за Х?
    НСВК: ну как же, это ж EDI, пфф…
    Я: послушайте, мы поддерживаем SOAP, REST, JSONRPC…
    НСВК: нет, мы работаем только с EDI
    Я: вы хотите что бы мы реализовали у себя на стороне поддержку этого ммм… протокола? Посоветуйте хотя бы какие-то оббертки совместимые (по опыту с SOAP знаю что не каждый клиент понимает какждый сервер и т.п.), я вот тут нашел на питоне bots, но он страшный какой-то (там зачем-то ему нужен сервер на джанго чтоб конвертить хмл в EDI)…
    НСВК: (приаттачивает непонятных людей в СС с мейлами из OpenText)
    Люди с мейлами из OpenText: здравствуйте, мы компания OpenText, крупнейший интегратор EDI, приходите на наше демо

    Демо:
    Мы многомиллиардная корпорация (действительно, слайды с ревеню зашкаливающие), мы нарисовали схему, вот тут вы, тут мы, а тут ваш НСВК.
    Заманчивый слайд с ценами, всего порядка нескольких десятков К долларов с лица (включает стажировку и курсы специалиста по настройке конвертора ХМЛ в EDI).

    Занавес.

    А вы говорите REST или JSON-RPC…


    1. Crandel
      21.12.2017 18:52

      Тоже работал над EDI -> XML и наоборот, как же я ненавидел этот проект!!!


      1. Gemorroj
        21.12.2017 19:09
        +1

        Тоже с EDI работаю, у нас REST еще не изобрели. Варианты интеграции SOAP или файлики на FTP сервере которые по интервалу забираются =)
        При чем что-то менять по технологиям ни в какую, мягко говоря очень консервативный подход.


        1. Crandel
          21.12.2017 19:12

          У нас попроще, делали консольную утилиту на джаве используя код из MapForce, которая собирала все файлики из директории и ложила результат в отдельную папку


    1. vlsinitsyn
      21.12.2017 21:21

      EDI любят всякие финансисты, так что с ним придется жить.
      В муле есть коннектор. В принципе, он и закрывает у нас все вопросы по теме.


      1. robert_ayrapetyan
        21.12.2017 22:40

        Клиент был не финансист, а транспортная компания (used-car retailer из fortune top 500)


        1. vlsinitsyn
          21.12.2017 23:01

          Ну, одно другого не отменяет.
          На самом деле, если уж по-честному, обленились вы там, ребята.
          Все вам на блюдечке подавай.
          Стандарт старый, спецификацию в руки, и вперед.
          Ничего там сверхъестественного нет.
          Ну а курсы и т.д. — это бонус. Хорошо, когда есть.


          1. robert_ayrapetyan
            21.12.2017 23:13

            Я был не против, если бы была либа-оббертка. Но ее нет! Есть какие-то велосипеды под .NET, и монстроузные интеграторы типа OpenText и bots. Стандарт хороший, основан в послевоенные годы (и не менялся), но с другой стороны — для всего хорошего есть куча бесплатных человеческих АПИ, а для EDI нет, там все коммерческое и стоит баснословных денег, это очень подозрительно как-то.
            Не, ради двух АПИ городить поддержку EDI, даже ради такого важного клиента, не знаю…


            1. vlsinitsyn
              21.12.2017 23:20

              Ну, какие проблемы — напишите и выложите в паблик забесплатно.
              Не нашлось видимо пока желающих — жадные все :-).


              1. robert_ayrapetyan
                21.12.2017 23:31

                Насколько я успел понять (глубоко не вникал, конечно), там под каждую интеграцию нужно свою либу писать, универсальный враппер пытались родить на основе каких-то файлов-конфигов мета-описаний, но это все ужас ужасный, зачем?? Нам нужно получить 10 полей и ответить ОК или ошибка, все.
                bots этот питоновский, с админкой на джанге…

                Представляете, если б для интеграции по JSON-RPC или REST вам на полном серьезе предлагалось поднять у себя особый сервер, пойти в админку, нарисовать там какие-то схемы, соединить все правильно, написать кучу текста мета-описания, все это для того чтобы сгенерить ХМЛ, который потом сможет прочитать ваш софт! В топку весь этот EDI


                1. mayorovp
                  22.12.2017 08:53

                  Представляете, если б для интеграции по JSON-RPC или REST вам на полном серьезе предлагалось поднять у себя особый сервер, пойти в админку, нарисовать там какие-то схемы, соединить все правильно, написать кучу текста мета-описания, все это для того чтобы сгенерить ХМЛ, который потом сможет прочитать ваш софт! В топку весь этот EDI

                  Вообще-то именно так и работают интеграционные шины (ESB). И в топку нужно выкинуть именно их, а не EDI :-)


                  1. robert_ayrapetyan
                    22.12.2017 09:00

                    Ну как можно любить EDI, не понимаю. Например:

                    ISA*00*Authorizat*00*Security I*01*Interchange Sen*01*Interchange Rec*170626*1338*^*00501*000000001*0*I*+
                    GS*SM*Application Sen*Application Rec*20170626*1338*1*T*005010
                    ST*204*0001
                    B2**STAN**Shipment Identification Number**TP
                    B2A*00*LT
                    L11*DATE: 20170630 TIME: 053000*P8
                    L11*MEDIUM*AFG
                    G62*TA*20170626*0*1338
                    AT5***FUEL SURCHARGE
                    RTT*CO*999.99
                    AT5***BASE COST
                    RTT*CO*9999

                    Сравните с:
                    «date»: «20170630»,
                    «fuel_surcharge»: 999.99,
                    «base_cost»: 9999

                    Вы какой вариант предпочтете для интеграции?


                    1. mayorovp
                      22.12.2017 09:24

                      Для интеграции с уже готовой системой я предпочту тот формат, который той самой системой поддерживается :-)


                      Да, то что вы привели — выглядит некрасиво. Но я не вижу технических сложностей ни в том чтобы такое сообщение сформировать, ни в том чтобы его распарсить.


                    1. MacIn
                      22.12.2017 22:30

                      Вы какой вариант предпочтете для интеграции?

                      Тот, который нужен клиенту и за который платят деньги.


                      1. justboris
                        22.12.2017 22:39

                        А если клиенту подойдут оба и заплатят одинаково?


                        1. MacIn
                          22.12.2017 22:42

                          В обсуждаемой ситуации, как видим, такого не наблюдается.
                          Обсуждается именно «я хочу так, но клиент-бяка не согласен, и плевать, что у него уже тонны софта под этот стандарт написаны».
                          Так-то, конечно, можно выбрать то, для чего есть готовые библиотеки и для чего решение можно слепить быстро.


                          1. robert_ayrapetyan
                            22.12.2017 22:46

                            Если у клиента тонны софта под EDI, пусть удосужиться написать оббертку человеческую, я уверен они не от нас первых такое услышали (клиент на рынке — с 1993 года, уверен, что их многие посылали за 25 лет с их OpenText-ом подальше).
                            Наша жизнь слишком коротка, чтобы плодить велосипеды на стандарты 60-х годов в 2017, как-то так…


                            1. MacIn
                              24.12.2017 04:04

                              Если у клиента тонны софта под EDI, пусть удосужиться написать оббертку человеческую

                              Щито? Клиент нанимает разработчиков, и он им еще должен писать обертки? Потому что они хотят работать по системе тяп-ляп и готово?

                              Наша жизнь слишком коротка, чтобы плодить велосипеды на стандарты 60-х годов в 2017, как-то так…

                              Так в чем проблема? Придет другой подрядчик и напишет.


                              1. robert_ayrapetyan
                                24.12.2017 08:09

                                Тут нет отношений подрядчик\заказчик. Есть две компании, одинаковые по сути, и им нужно интегрироваться, взаимовыгодное сотрудничество так сказать…


    1. Wayfarer15
      21.12.2017 21:30

      Ощущение, что говорят два пипла, один про payload, другой про транспортный протокол (т.е. EDI over SOAP/REST и прочее).
      А пример этого самого EDI? Ну и потом, а какой-нибудь integration engine использовать не пытались, нет, оно там возможно уже сделано.


      1. robert_ayrapetyan
        21.12.2017 22:44

        Ну вон они пытались пытались продать OpenText решение для интеграции (с курсами, специалистом и всем), не поверите — там два апи по 10 параметров в каждом! У нас подобных (идентичных даже) интеграций десятки, все без привлечения специалистов сторонних и десятков К.


    1. MacIn
      22.12.2017 22:27
      -1

      Я: вы хотите что бы мы реализовали у себя на стороне поддержку этого ммм… протокола? Посоветуйте хотя бы какие-то оббертки совместимые

      Херакс, херакс и в продакшн не получилось. Верно сказали выше — обленились вы, ребята.


      1. robert_ayrapetyan
        23.12.2017 01:57
        +1

        Не минусил если что.
        Я не согласен, что по щучьему велению клиента, или за деньги компании, нужно кидаться реализовывать решения любой степени маразматичности. Понятно, что можно прочитать их мануал на 300 страниц, постичь все аббревиатуры и посчитать звездочки правильно и за пару недель наговнокодить энкодеры\декодеры, но я просто не буду этого делать.
        Более того — OpenText не заинтересован в таком исходе, их цель — продать своих ребят, свой софт и себя, поэтому никакого содейсвтия не будет.
        А мне потом еще месяцами разгребать баги и искать где звездочка пропущена, извините!

        Схема, конечно гениальная! Все понимают что EDI — нездоровая хрень и атавизм в 2017, но мы вас всех готовы спасти, только заплатите.


        1. MacIn
          24.12.2017 04:07

          Схема, конечно гениальная! Все понимают что EDI — нездоровая хрень и атавизм в 2017, но мы вас всех готовы спасти, только заплатите.

          Есть программисты, которые хотят переписать все с нуля на модном стеке, а есть бизнес, которому лучше держать таких специалистов от себя подальше. Нет смысла сливать уже оплаченный софт, часы разработки в унитаз, из-за того, что кто-то весь такой модный и в белом пальто хочет иметь красивую строчку с модными технологиями в резюме. Здесь устремления конкретного человека-разработчика и бизнеса не пересекаются.


          1. robert_ayrapetyan
            24.12.2017 04:47

            Еще раз — речь идет о двух функциях с нексолькими параметрами в каждой, вся бизнес-логика давно написана. Проблема именно в оббертке над EDI, ее никто не хочет писать (ни мы ни они). И есть компания-интегратор, которая на оббертке зарабатывает огромные деньги. В этом и есть идиотизм ситуации, они сидят на крючке у интегратора и всасывают новых партнеров туда же… вы не сталкивались с ANSI X12, поэтому вам все это кажется странным.


            1. MacIn
              24.12.2017 17:11

              Я сталкивался с кучей разного легаси, в том числе с необходимостью выгрузки данных в 7 битной кодировке, потому что весьма рупная страховая компания в США обрабатывает данные на старом mainfram'е, использующем ее. Странным все это не кажется, legacy — часть жизни. Никто не будет выбрасывать работающее просто «потому что».


            1. VolCh
              24.12.2017 17:23

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


  1. DieSlogan
    21.12.2017 18:27

    А как же OpenAPI aka Swagger?
    Я всю жизнь сидел на SOAP только потому, что не очень удобно писать десериализаторы на клиенте под крупные JSON/XML данные, а тут такая конфетка, что аж руки зачесались применить её в каком-нибудь API.


    1. sayber
      21.12.2017 19:52

      Swagger — просто интерфейс по сути, который описывает I/O.
      Дальше уже обычный REST с PUT/PATH/POST/GET/OPT… etc.


      1. ffriend
        21.12.2017 20:16

        По Swagger / OpenAPI описанию можно генерировать клиента (например), плюс многие библиотеки сразу дают красивый UI с примерами запросов, от чего клиенты обычно в восторге.


        1. sayber
          21.12.2017 20:18

          Спасибо, но я в курсе.
          Пользуемся swagger давно, для API всех букинг проектов.


    1. Pilat
      22.12.2017 04:27

      Этот OpenAPI показал себя в полной мере после появления версии 3. Поддержка версии 2 была уничтожена в Eclipse — поддерживает его одна компания и их не интересует ничего кроме их же SwaggerHub. Фактически OpenAPI/Swagger — проект одной компании. Вторая версия вообще не позволяла описать некоторые важные моменты, третья позволяет, но не реализована для некоторых языков. Дурацкая ситуация — наработано всё под swagger2, а Eclipse ставит пакет для несовместимого swagger3 :) И по сложности от SOAP ушло всё это недалеко.


  1. arturpanteleev
    21.12.2017 20:10
    +2

    Статья, мягко говоря, неодноззначная. Вот есть подробный ответ на неё, там автор хорошо разобрал всё philsturgeon.uk/api/2017/12/18/rest-confusion-explained


  1. vladqa
    21.12.2017 20:11

    Поэтому мы забили на REST и перешли на gRPC. Стало гораздо удобнее и однозначнее.


    1. unsafePtr
      22.12.2017 04:08

      Одно но, он веб как бы не поддерживает. Есть костыли от сторонних разработчиков которые пытаются приспособить его к вебу, но если сам гугл не сделал такой поддержки, значит оно ему и не нужно. gRPC скорее больше нужен как межсервисная коммуникация. Кстати по опыту CLI protobuf-a просто ужасен.


      1. vladqa
        22.12.2017 06:11

        Мы приспособили его к web с помощью grpc-gateway. Да, оно конвертит в тот же пресловутый json, но на стороне сервиса мы все еще пишем api на gRPC и не пытаемся заигрывать с REST. Сейчас также изучаем возможность работы с нативным gRPC на клиенте.


        CLI действительно менее удобный. Однако, по сравнению с сваггером (OpenAPI) тут есть вменяемый красивый DSL.


        1. unsafePtr
          22.12.2017 10:24

          Если честно, я бы просто хотел генерировать модельки описанные в IDL. Если задуматься, имея готовые модели, можно не заморачиваться со спецификой protobuf протокола, и возвращать обычный json из уже готовой модели(так как для json-a у них свои ). Ну а сервисы, можно будет самому написать, без gRPC. Ведь кому-то нужен REST, а имея на руках готовые модели мы точно знаем какой объект нам придёт, за разработчиком остаётся только определить входные точки(endpoint). Кстати, не пробовали ли вы thrift? Ну я нарыл на днях решение от майкрсофта, где есть дженерики. Они, между прочим, тоже решили следовать gRPC.


          1. vladqa
            22.12.2017 22:22

            REST, на мой взгляд — достаточно ущербный стиль взаимодействия, который добавляет больше проблем и неоднозначностей, чем решает. Далеко не любые бизнес-процессы можно выразить с помощью REST: если у вас что-то сложнее чем CRUD, то начинаются проблемы. Ведь в REST мы говорим существительными и оперируем ресурсами. В классическом RPC — глаголами. Бизнес-процессы удобнее выражать глаголами.


            Что касается gRPC: у нас много сервисов на разных ЯП и нам удобно:


            1. Описывать API одинаково и на нормальном языке.
            2. Генерировать из него клиенты и серверы. Весь тулинг официальный и активно поддерживается. Сами proto-файлы с описанием сервисов мы подключаем субмодулями в нужные проекты. Все стандартизировано и достаточно удобно. Само API проходит code review.

            Честно говоря не очень понял, что имеется в виду под "спецификой protobuf-протокола", т.к. protobuf — это способ сериализации данных со схемой. Лично нам он очень приглянулся из-за его однозначности и удобства для восприятия. Также классная штука oneof: очень удобно возвращать ошибки из метода.


            Ребятам на фронтенд мы тоже даем читать обычные proto-файлы. В них есть и информация о том, как вызвать метод по http и все структуры прозрачно конвертируются в json. Это все вместо (имхо), совершенно неадекватного описания web-api через тот же сваггер, которое больно читать.


            Также есть реальная надежда на приход gRPC на фронтенд в полном виде. В этом случае у нас все готово: убираем конвертацию в json и все.


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


  1. vedenin1980
    21.12.2017 21:04

    REST — это новый SOAP.


    Да ну, SOAP тоже иногда нужен и полезен. У Rest своя ниша, у Soup — своя, у RPC и message query — своя. Главный плюс REST — его поддерживают почти все, поэтому любой сервис на REST можно переписать на любой другой язык. Это очень важно для бизнеса и вряд ли другая технология может его там подвинуть.


  1. baul
    21.12.2017 21:17

    Паршивое решение: ваш nginx был ошибочно сконфигурирован на один час, так что пользователи вашего API получают только ошибки 404 и вычищают сотни аккаунтов, думая, что они удалены

    Паршивое не решение, а конфигурация nginx. Не надо перекладывать все с больной головы на здоровую.


    1. y90a19
      21.12.2017 21:26
      +1

      паршивое решение — смешивать бизнес-логику и протокол передачи данных. Давайте уж на команды TCP завязываться, хуле.
      Это разные уровни, их нельзя смешивать. Как нельзя смешивать TCP и HTTP.

      И уж тем более невозможно уберечься от падения. А обвинять в «криворукости» — это подход прыщавой школоты


    1. MacIn
      22.12.2017 22:35
      -1

      Решение в самом деле паршивое.

      Представьте, что у вас есть некий охраняемый объект и есть датчик открытия двери. Пусть он нормально разомкнутый, а при открывании замыкает цепь. Реализуется просто — появилось напряжение на вводе — сигнал тревоги. И все хорошо, но если провод поврежден или просто откушен — система не сработает. И можно сколько угодно топать ногами, гневно восклицая, что монтажники — дураки, проложили кабель в видном месте и вообще что он не заминирован и не надо, мол, с больной головы на здоровую перекладывать. Сделать это идеально не получится и все равно система даст сбой рано или поздно. И эта возможность отказа заложена в самой системе, это и есть «паршивое решение».


  1. y90a19
    21.12.2017 21:18

    По мне так самым удобным был wsdl — в xml было описание всех возможных запросов, форматов запросов и ответов, виды ошибок.
    И протокол сам следит за корректностью данных, чтобы они соответствовали шаблону. Полный ordnung. Опять же автоматическая генерация кода сервисов на основе этой wsdl


    1. vlsinitsyn
      21.12.2017 21:28

      Проблема WSDL даже не в сложности самого стандарта, а в реализациях библиотек, когда какие-то фичи поддерживается, другие — нет. Не от хорошей жизни начали выдумывать Basic Profile…
      А XML — да, мне кажется более надежным чем JSON. Поддержка везде, в самых экзотических системах. Нативная поддержка в Java. Для сравнения, JSON схема 4 — все еще в драфте, а библиотека для Java — сторонняя опенсоурсная, распавшаяся в свое время на два не полностью совместимых бранча.


    1. vedenin1980
      21.12.2017 21:29

      wsdl — это и есть SOUP, который как раз представляют в статье совсем уж пугалом. На самом деле, SOUP при всей своей громоздкости и сложности вполне имеет нишу и все еще жив.

      SOUP это операции, порядок, секюрность, транзакции, сложность,
      REST — простота, работа с ресурсами, веб,
      RPC — завязка на одну технология/язык + производительность.
      Message query/RabbiteMQ и т.п. — завязка на одну MQ систему, локальность, надежность и производительность.

      У каждой технологии своя ниша.

      Нативная поддержка в Java. Для сравнения, JSON схема 4 — все еще в драфте, а библиотека для Java — сторонняя опенсоурсная, распавшаяся в свое время на два не полностью совместимых бранча.

      Не одна их много, есть нативная поддержка json в JEE. Да и какая разница, если все равно все пользуются? Как будто последную версию xml java может не поддерживать.


      1. Lyazar
        22.12.2017 10:04
        -1

        SOUP это операции, порядок, секюрность, транзакции, сложность,

        Пока XXE какой-нибудь не встретится в запросе.


    1. lair
      22.12.2017 00:16

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

      Не, не следит. Можно иметь WSDL, несоответствующий ему сервис и пейлоад, и все равно все будет работать. Или не будет. Или можно заслать все строго согласно WSDL и получить болт в ответ.


  1. VolCh
    21.12.2017 21:28

    Основная проблема "REST", как я считаю, что мало кто понимает, что HTTP — это уже практически REST API, заточенный под, как ни странно, под веб-странички. Если ваша предметная область плохо ложится на них, то не надо насиловать ни себя, ни HTTP пытаясь натянуть первое на второе, сделайте один или несколько ендпоинтов и используйте HTTP в качестве транспортного протокола, а не прикладного. Прикладной реализовать можно полностью в теле HTTP запроса, можно использовать какие-то другие его части (заголовки, url, query, коды возврата), но не стремитесь соблюдать его семантику больше чем того требуют практические, большей частью технические соображения, типа способность клиента кэшировать HTTP или способность PHP выбирать файлы из запроса.


    Нравятся принципы REST — реализуйте API по этим принципам, передавайте от сервера к клиенту представления состояний, не храните сессию на сервере, передавайте все необходимые данные для операции в запросе клиента к серверу и т. п. (6 принципов REST вроде) Но передавайте всё это так, как вам удобно, создавайте свои типы действий, свои схемы идентификации ресурсов и т. д.


    Только не надо говорить, что это получится RPC — оперировать вы будете представлениями состояний ресурсов и операций над ними. Что хорошо ложится, кстати, на ООП: состояние ресурса — объект, действие — метод, представление — кастомная сериализация объекта. А RPC — процедурщина :)


    1. MacIn
      22.12.2017 22:38

      используйте HTTP в качестве транспортного протокола, а не прикладного. Прикладной реализовать можно полностью в теле HTTP запроса, можно использовать какие-то другие его части (заголовки, url, query, коды возврата), но не стремитесь соблюдать его семантику больше чем того требуют практические, большей частью технические соображения, типа способность клиента кэшировать HTTP или способность PHP выбирать файлы из запроса.

      Тогда уж лучше WebSocketы использовать, зачем гвозди микроскопом забивать…


      1. VolCh
        23.12.2017 13:01

        WebSocketы не везде хорошо поддерживаются, или точнее, много где хуже чем старый добрый HTTP.


  1. rsvasilyev
    21.12.2017 22:03
    +2

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


    Лайк в Facebook, отправка сообщения в Slack, свайп в Tinder, оформление заказа на Amazon или выстрел в какой-нибудь игрушке — все это действия, а не создание или модификация ресурсов.
    За ними скрывается куча побочных эффектов типа отправки письма подтверждения или инкремента нескольких счетчиков.


    Можно прятать вызов "like(id)" за запросом к "POST /resource/id/likes", но зачем?


    1. VolCh
      21.12.2017 22:33
      +1

      А можно сделать


      POST /rest-api
      Content-Type: application/x.my-cool-rest-api+json
      
      {
        "resource_id": "id",
        "action": "like"
      }

      и это будет REST :)


      1. symbix
        22.12.2017 02:11

        Тут идеологи RESTFUL возразят, что, по определению, "REST API" — это API, соответствующее определенным архитектурным требованиям, и не является объектом (поскольку определение описывает не объект, а концепцию).


        Вдохновимся CQRS и разделим все на "запросы" и "команды". С запросами в рамках REST обычно проблем ни у кого не возникает, вся (вполне справедливая) критика REST относится к командам. Окей, пусть команды будут ресурсами, и в рамках REST мы создаем команду (которая немедленно выполняется и, выполнившись, удаляется — вот такая деталь реализации ресурса, почему нет?):


        POST /commands
        
        {
             "name": "registerUser",
             "params": {...}
        }

        Напоминает RPC, правда? :-)


      1. BlackSCORPION
        22.12.2017 10:04
        +1

        Интересно что вернет GET "/rest-api" :)


        1. oxidmod
          22.12.2017 10:44

          Список доступных action-ов?

          Почему вы думаете, что если есть POST /rest-api, то результатом GET /rest-api должна быть коллекция тех ресурсов, что созданы постом?
          Да, это распространенная практика, но не требование. REST требует, чтобы ресурс можно было идентифицировать однозначно, но не требует совпадение URL-ов.

          Запрос:

          POST /rest-api
          Content-Type: application/x.my-cool-rest-api+json
          
          {
            "resource_id": "id",
            "action": "like"
          }
          


          Ответ:
          201 CREATED
          Location: /rest-api/likes/{like_id}
          


  1. babylon
    21.12.2017 23:04

    В чем проблема использовать MessagePack-RPC и его аналоги? Разобрали — передали — собрали. Не хотите разбирать — не разбирайте. Посылайте как есть. Нужны иерархии? Не вопрос.


  1. zoryamba
    22.12.2017 10:04
    -1

    тут нужно вспомнить, для каких целей изначально создавался HTTP протокол. как по мне — REST покрывает эти цели на 100%. попытки впихнуть в HTTP что-то большее являются костылями изначально. как и все современное web-программирование в принципе…


  1. kirinaa
    22.12.2017 10:04

    Все по делу


  1. denis-vc
    22.12.2017 10:04
    +1

    КО утверждает:
    1) Простые вещи должны делаться просто. И их проще несколько раз переделывать целиком, чем обеспечить стабильность-совместимость-и-непротиворечивость-на-века-аминь.
    2) Типовых задач — больше 80%. А значит, простые решения будут востребованы всегда. Любая «расширяемая» парадигма, должна уметь деградировать до «hello world», чтобы получить шанс попасть на этот праздник жизни.
    3) И тем не менее, взгляд на то, как наилучшим образом решать типовые задачи, имеет каждый суслик в поле. Без этого прогресса не будет, хотя и неразберихи тоже полно.
    4) Решение сложных задач — это всегда вызов. Иначе они не назывались бы сложными. Более того: сложная задача сегодняшнего дня может перейти в статус типовой завтра. При решении сложных задач приходится сталкиваться с границами возможностей всего: железа, софта, спецификаций. И иногда приходится изобретать своё, чтобы расширить границы возможного.
    5) Автоматизация разработки и её человекоориентированность — это разные цели. Порой, диаметрально противоположные. Для машины удобнее xml, wsdl и прочие строгие вещи. Для человека — html, json (как html, только для ajax). И тут снобизм неуместен: интернет как явление мог бы не состояться, если бы не было простого html и браузеров, очень терпимых к ошибкам в нём. В простых задачах сначала идёт человекоориентированность. И только по мере усложнения и развития приоритет автоматизации усиливается.
    6) Интероперабельность, совместимость, интеграция — это задача в третьем измерении, которая решается с учётом первых двух. Если вообще возникает. В огромном числе простых задач — вопросы интероперабельности отсутствуют как класс. Хоть на коне танцуй!

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

    С другой стороны, запрос на строгость и спецификации есть. А значит будут и спецификации и их достаточно широкая поддержка. Чтобы ещё какое-то подмножество сложных задач стало типовыми.


  1. Cromathaar
    22.12.2017 13:04
    +1

    Сдается мне, что автор начал за здравие, а закончил за упокой. Зачем это сопоставление REST с CRUD? Причем здесь проблема N+1? Сервисы — это фасад, и должны им оставаться. Обслуживающий персонал. Ну надо клиенту получить много связанных данных — ну выстави ты ему агрегирующий ресурс, зачем повторять структуру домена или структуру таблиц в БД? С таким успехом сервисы на основе чего угодно можно сделать эдакой вещью в себе.


  1. amarao
    22.12.2017 14:15

    Я рад, что эту статью перевели. Я начинал её читать со скеписом, но они меня переубедили.

    Люди любят REST за две вещи:
    * Сохранять простое простым
    * Человекочитаемые URL'ы.

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


  1. springimport
    22.12.2017 21:16

    Для меня Swagger оказался открытием и довольно приятным в использовании. Для работы нужно было работать с magento 2 devdocs.magento.com/swagger
    Конечно, огорчает клиент под php где среднее качество кода и нет интерфейсов для удобной работы с DI. Еще хотелось бы лучшую поддержку ошибок. И все же плюсов гораздо больше.

    Возможно идеальный протокол и должен быть easy to learn, hard to master.


  1. qbnumberus
    23.12.2017 23:23

    Very nice post and really appreciable.
    By QuickBooks Support