Re[3]: REST: прохой\хороший интерфейс
От: Sinclair Россия https://github.com/evilguest/
Дата: 07.02.20 07:10
Оценка: 52 (7)
Здравствуте, Буравчик, Вы писали:

Б>Все, что можно сделать в REST, можно и в RPC.

Б>Хотелось бы услышать список преимуществ REST перед RPC.
Основное преимущество REST — более "естественная" поддержка неидеальности мира.
Основная модель RPC — это "black box", инкапсуляция поведения и состояния. Когда его проектировали, казалось, что это — хорошая идея; потому что она привычна императивным разработчикам, и позволяет изолировать подсистемы.
Б>Основное различие — REST оперирует ресурсами, а RPC — операциями.
REST оперирует состоянием. Самый простой пример: RPC говорит "включить свет", а REST говорит "свет должен стать включенным".
Семантической разницы, вроде бы, нет. Но есть разница в том, как обрабатывать сбои.
Б>Но при проектировании обычно так: У нас есть 10 операций, давайте натянем их на REST (спроектируем ресурсы, применим к ним глаголы).
Это с непривычки. Ну, как начинающий студент сначала строит фразу на родном языке, а потом переводит её на иностранный. А опытный — сразу думает готовыми конструкциями целевого языка.
Так и тут — опытный архитектор сходу видит в системе то состояние, которое он будет реплицировать.

Потом в документации напишем, чтобы выполнить операцию 1 — работаем с такими-то ресурсами, операцию 2 — с такими-то.

Б>В RCP ничего этого не надо — есть операция, есть вход, есть выход.

Вот именно это и плохо. RPC провоцирует людей думать о happy path, и вообще не задумываться о плохом — типа: а что делать, если "выход" потерялся.
REST, при последовательном следовании ему, заставляет проектировать систему надёжным образом.
К сожалению, вот именно это последовательное следование — большая редкость. Очень часто люди проектирут именно так, как вы сказали — вот 10 операций, давайте сделаем их POST-ом. Ну, то есть в RPC у нас было что-то типа
POST /lightOperations

{
   "operation":"switch",
   "targetLamp": 2144,
   "targetState": "on"
}


Вообще, из практики, бывает даже так, что из требований програм менеджера "должно поддерживаться включение/выключение света" ничего, кроме ровно этого метода, не происходит. Я не шучу — именно так был устроен MOSI API, созданный Microsoft примерно в 2011 году. Он был write only. Но если програм менеджер был более внимателен, или архитектор чуть менее идиот, то у нас будет работать и примерно вот такое:
POST /lightOperations

{
   "operation":"get",
   "targetLamp": 2144,
}

Когда разработчику, искалеченному RPC, ставят задачу "перевести всё на REST", он зачастую делает вот так:
GET /lamps/2144

Это аналог нашего "operation":"get" из предыдущего примера. Сразу получаем два преимущества перед RPC:
1. На этот раз архитектор не смог забыть про возврат состояния.
2. Запрос состояния сделан глаголом GET, и вся инфраструктура сразу же понимает последствия: результат запроса можно кэшировать; его можно смело повторять при сбое коммуникации, не боясь ничего сломать; получив 302 или 301 мы точно знаем, что можно безопасно следовать по указанному URL.

"Плохой" рест-архитектор затем делает вот так:
POST /lamps/2144/switch?state=on

Почему так делать плохо? Есть ряд причин:
1. Как обрабатывать двойное включение? Допустим, лампа уже on. Хочется вернуть 409 Conflict, но нельзя — возможно, клиент сделал POST, получил 502, и пытается снова. Увидев 409, он решит "я не смог включить" и запишет это как сбой.
Считать это успехом?
2. Что возвращать при успехе? 200 Ok? А в body что? Если состояние лампы, то это плохо — мы вынуждены протаскивать весь документ. Наверное, надо делать redirect-on-post и перекидывать на lamps/2144, и уже оттуда клиент получит состояние. Это даёт ему шанс, к примеру, получить delta-encoding, и при наличии в кэше предыдущего образца хорошо сэкономить на трафике.
3. В любом из вариантов нет связи между состоянием лампы и этим запросом. То есть, скажем, прокси, который хранит у себя /lamps/2144, должен каждый раз бегать на origin сервер с conditional get, чтобы держать кэш когерентным.

Если у нас чуть более сложная операция, вроде "увеличить яркость на 10%", то всё становится ещё хуже — в рамках RPC мы вообще не можем отличить потерянный POST от последовательного увеличения яркости. Если для switch?state=on у нас есть очевидная стратегия обработки повторных запросов (хотя бы на сервере), то для вот таких вот операций ничего хорошего нету.

Очень, очень велики шансы на то, что архитектор просто забудет об этом подумать. Потому что очень редкий програм или продакт менеджер расписывает все вот эти вот сценарии вроде "что делать, если запрос клиента не доехал до сервера", "что делать, если ответ сервера не доехал до клиента", "что делать, если между повторными запросами вклинился другой клиент с конфликтующим запросом" и прочие детали.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[9]: REST: прохой\хороший интерфейс
От: Sinclair Россия https://github.com/evilguest/
Дата: 11.02.20 07:54
Оценка: 80 (4) :)
Здравствуйте, samius, Вы писали:

S>Сам Филдинг упоминает о том, что РЕСТ основан на совокупности стилей, перечисленных в главе 3 его диссертации. Один из — Client-Stateless-Server (CSS), описанный в 1994-м (https://www.ics.uci.edu/~fielding/pubs/dissertation/net_arch_styles.htm). РЕСТ — всего лишь гибрид. В любом случае, Филдинг не преподносит его как изобретение. Объединение, наследование — да. И по сути этого объединения вышло так, что работа с состоянием не выглядит в этом объединении ключевой. Безусловно является, но не выглядит таковой. Замылилась репрезентативностью.

Эмм, не знаю насчёт "замылилась". У Филдинга representational означает, что мы не лезем в состояние сервера напрямую. Всё, что у нас есть — некоторое представление этого состояния; и вся коммуникация между клиентом и сервером выражена в терминах этого представления.
И, с точки зрения Филдинга, REST — первичен, как абстрактная модель. HTTP 1.1 — это, с его точки зрения, всего лишь пример применения концепции REST к World Wide Web. (Глава 6.3).

S>>К сожалению, с публикаций первоисточников прошло много времени. В интернет набежала толпа недоумков, которые слышали про REST только в пересказе других недоумков. Они думают, что REST — это любой JSON over HTTP.

S>>Не надо их читать. Надо читать классику типа http://shop.oreilly.com/product/9780596529260.do.

S>Читать — это хорошо. Свой API можно сделать правильно и избежать некоторое кол-во проблем. Проблема-то несколько в другом. Есть некоторое кол-во сервисов, предоставляющих REST API в духе JSON over HTTP (не вдаваясь в математику HTTP). Как клиенту мне сложно с ними дискутировать о том, каких недоумков им не нужно читать, проектируя REST API. Дешевле закостылить клиента, чем сподвигнуть сервис на переписывание API по фен-шую.

Это понятно. Мы не можем изменить прошлое.
S>Хочется сказать им: ребята, надо делать вот так ... Но у Филдинга слово "идемпотентность" в работе не упоминается, а на каждую книжку, где оно упоминается вместе с REST, найдется пяток таких книг, где его нет.
Ссылайтесь на книжку Руби и Ричардсона. Она — правильная. И доступна бесплатно.
Вот прямо сейчас мы изменяем будущее — этот форум читает человек пять, из них, может быть, 2% будут когда-то иметь отношение к проектированию веб-сервисов.
Важно, чтобы хотя бы они умели отличать хорошее от плохого. Нужно вовремя им показать правильную книжку.
И быть готовыми отвечать на каверзные вопросы — а то вон, оказывается, можно даже собственный прокси-сервер реализовать, так и не поняв, как REST и HTTP помогают дизайнить хорошие API.

По хорошему, надо расширять евангелическую деятельность. В надежде, что пропаганда однажды зацепит людей в Редмонде, Купертино, и прочих Менло Парках.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[3]: REST: прохой\хороший интерфейс
От: Sinclair Россия https://github.com/evilguest/
Дата: 03.02.20 10:01
Оценка: 14 (3)
Здравствуйте, ylem, Вы писали:

Y>Если я неправильно смотрю на весь дизайн, то как правильно, при условии, что объект есть, и только штука с интерфейсом знает, как его правильно двигать и плющить.

Вообще-то я остерегаюсь дизайнить слона по требованиям к мочке уха.
1. Что такое "модель объекта"? Сколько таких моделей используются согласованно? Т.е. мы говорим о целой сцене, в рамках которой (почему-то) хочется отдельно запрашивать/модифицировать отдельные объекты, или о "монолитном" объекте, который сам по себе, и у него есть привязка к координатам.
2. Какие ещё операции должны быть доступны, и насколько часто они выполняются?

В простом случае мы говорим о некотором "документе", который описывает весь объект, как он есть. Ну там — вершины, рёбра, грани. Массив точек, массив треугольников.

Операция "изменить объект" — это просто PUT с новым объектом. REST — он про состояние, а не про инкапсуляцию, где "только штука с интерфейсом знает, как его двигать".
Чтобы сделать "штуку с интерфейсом, которая знает как правильно двигать", нам достаточно иметь совершенно отдельный safe метод transform.
Мы отдаём ему на вход детальное описание объекта и описание трансформации, а на выходе он выдаёт нам новое описание объекта.
Примерно так работал google maps в те доисторические времена, когда рендер SVG был невероятной экзотикой. И у них была ферма серверов, которые умеют превращать SVG в PNG.

Так и здесь: выполняем GET /transforms/rotateEulerAngles/35.3,123,2,0.0/{тутОписаниеОбъектаВкомпактномПредставлении}/, получаем новое описание объекта.
Преимущество тут в полном отсутствии состояния — мы можем раскидать эти запросы по 1000000 геораспределённых машинок. То есть эта часть сервиса — safe & stateless.
Потом, совершенно отдельно от этого сервиса, делаем PUT /objects/{objectsId}/{тутОписаниеОбъектаВкомпактномПредставлении} — он уже вполне себе идемпотентен.

Но это — кирпичики. Как из них сделать то, что нужно — вопрос открытый. Потому, что подобный дизайн всё ещё провоцирует интересные ситуации.
Скажем, клиент А прочитал состояние объекта, клиент Б прочитал состояние объекта.
Теперь клиент А пытается записать в объект "сплюснут", а Б — "сдвинут". В зависимости от порядка обращения и надёжности каналов, выиграть может любой. Это, очевидно, очень плохо.

Не имея реального ТЗ, мы не можем понять, что именно ожидается в результате такого сценария:
  1. применится только одна трансформация (заранее неизвестно, какая), вторая получит 409 conflict
  2. применяется результат той трансформации, которая вычитала объект первой; вторая получит 409 conflict
  3. применятся обе трансформации, в произвольном порядке (именно так работают, например, пополнения банковского счёта)
  4. применятся обе трансформации, в том порядке, как было выполнено чтение объекта.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re: REST: прохой\хороший интерфейс
От: Sinclair Россия https://github.com/evilguest/
Дата: 03.02.20 07:34
Оценка: 12 (1) +1
Здравствуйте, a.v.v, Вы писали:
AVV>вот хотел бы послушать коллективное бессознательное
Все предыдущие дискуссии по теме REST в этом форуме уже прочитаны?
Книга http://freecomputerbooks.com/Restful-Web-Services.html уже прочитана?

Тогда можно поговорить содержательно.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[3]: REST: прохой\хороший интерфейс
От: scf  
Дата: 31.01.20 14:15
Оценка: 10 (1) +1
Здравствуйте, ylem, Вы писали:

vsb>>1. Действия соответствуют семантике. GET возвращает, PUT кладёт, и тд. Кроме того соблюдается идемпотентность, т.е. можно вызывать GET или PUT сколько угодно раз с одними и теми же параметрами.


Y>Подскажите, пожалуйста, как правильный REST будет выглядеть для случая например:

Y>Есть модель объекта в обычном 3D пространстве и ее нужно сдвинуть на сколько-то в какую-то сторону.
Y>Если "сдвинуть" слишком просто, то чуть служнее: сплющить.
Y>А "идемпотентность" тут как-то можно соблюсти?

Y>Если я неправильно смотрю на весь дизайн, то как правильно, при условии, что объект есть, и только штука с интерфейсом знает, как его правильно двигать и плющить.


Y>Если расскажете, большое спасибо.

Y>Если не расскажите, просто спасибо, что дочитали

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

PUT /api/v1/model/{id}/position
PUT /api/v1/model/{id}/scale

Либо вообще
PATCH /api/v1/model/{id}

Если идемпотентность соблюсти нельзя, то ничего не поделаешь, придется делать без неё:

POST /api/v1/model/{id}/shift
POST /api/v1/model/{id}/scale

И обеспечивать отсутствие повторных запросов при реконнектах дополнительными заголовками а-ля X-Request-Id, чтобы сервер мог проверить, что этот запрос уже обработан.
Отредактировано 31.01.2020 14:16 scf . Предыдущая версия .
Re[4]: REST: прохой\хороший интерфейс
От: samius Япония http://sams-tricks.blogspot.com
Дата: 07.02.20 07:42
Оценка: 5 (1) +1
Здравствуйте, Sinclair, Вы писали:

S>Здравствуте, Буравчик, Вы писали:


Б>>Все, что можно сделать в REST, можно и в RPC.

Б>>Хотелось бы услышать список преимуществ REST перед RPC.
S>Основное преимущество REST — более "естественная" поддержка неидеальности мира.
S>Основная модель RPC — это "black box", инкапсуляция поведения и состояния. Когда его проектировали, казалось, что это — хорошая идея; потому что она привычна императивным разработчикам, и позволяет изолировать подсистемы.

Поставил "супер", но вот тут я принципиально не согласен. Не нужно противопоставлять RPC и REST вовсе. RPC — технология, позволяющая выполнить удаленный вызов и точка. REST — это архитектурный стиль организации работы распределенных приложений и сервисов. Это как сравнивать преимущества правил дорожного движения над автомобилем.
Re[11]: REST: прохой\хороший интерфейс
От: Cyberax Марс  
Дата: 04.02.20 18:59
Оценка: +2
Здравствуйте, Sinclair, Вы писали:

S>Понятно, что в общем случае "просто выбрать PUT" недостаточно; я вот прямо сейчас наблюдаю чудеса во вполне РЕСТ-овом API от Microsoft (https://docs.microsoft.com/en-us/partner-center/develop/partner-center-rest-api-reference), где парни ухитрились на ровном месте сделать невозможным предотвращение двоящихся или потерянных заказов.

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

S>Я так понимаю — как раз потому, что они не очень хорошо понимали, что такое REST, и задумывались о "стратегиях, которые гораздо важнее". Идемпотентность в старом order api они обеспечивали через custom header "Request-ID", а в новом shopping cart команде просто об этом хидере не рассказали.

Это одна из причин, по которой я не люблю REST. Информация слишком сильно размазана — по заголовкам, глаголу и телу запроса. Точно так же с ошибками — нет одного явного способа сообщать их.
Sapienti sat!
Re[6]: REST: прохой\хороший интерфейс
От: Serginio1 СССР https://habrahabr.ru/users/serginio1/topics/
Дата: 13.02.20 12:55
Оценка: 76 (1)
Здравствуйте, Sinclair, Вы писали:

S>Здравствуйте, Serginio1, Вы писали:


S>> Что скажешь по gRPC

S>>https://habr.com/ru/company/infopulse/blog/265805/
S>Надо читать. Выглядит подозрительно.

Вот нашел еще статью на Хабре
https://habr.com/ru/company/yandex/blog/484068/
и солнце б утром не вставало, когда бы не было меня
Re[21]: REST: прохой\хороший интерфейс
От: Sinclair Россия https://github.com/evilguest/
Дата: 14.02.20 05:39
Оценка: 21 (1)
Здравствуйте, Pavel Dvorkin, Вы писали:

PD>Ладно, пора заканчивать.

Ну естественно. Как дело доходит до конкретики, фанаты RPC разбегаются из треда.

PD>Ты упорно мыслишь в психологии HTTP.

Павел. Психология тут ни при чём.
PD>Какое такое перенаправление ? В HTTP — понятно, а в вызове процедуры на сервере о чем вообще речь может идти ? Я обращаюсь к серверу, вызываю его метод. Нет тут URL (точнее, он один был при соединении) и нечего перенаправлять. Если нужно, пусть сервер и перенаправляет куда хочет — тем же способом. Клиента это не интересует.
PD>Остальное аналогично. Пусть сервер там и разбирается, что modified, а что нет.
PD>Какие метаданные и в каких хидерах ? Нет тут хидеров и нет метаданных. Есть Person, которую надо с сервера получить. Здесь столько же метаданных и хидеров, сколько в SELECT * FROM persons WHERE
PD>Сжатие — ну если нужно, пусть метод делает zip и возвращает byte[] или ByteBuffer. thrift, кстати, ByteBuffer очень любит и все двоичные данные именно в виде его и передает
Павел, вот реально у тебя всё мышление с ног на голову повёрнуто. Пятнадцать лет на этом форуме — а ничего не изменилось.
Все рассуждения — на уровне байтовых буферов. "Нету хидеров и метаданных" — ну так это как раз и плохо!!!

Поясню ещё раз, в надежде, на проблески озарения.
Когда мы проектируем протокол, у нас задача не сводится к "передаче байтов по сети". Задача формулируется в терминах прикладных сценариев.
И в REST, даже если архитектор заранее не подумал о каком-то аспекте, то можно задним числом этот аспект добавить, не ломая прямую и обратную совместимость!
Одно это ставит REST на две ступени выше, чем любой RPC.
"Пусть сервер и перенаправляет" — отлично. Вот тебе сценарий: клиент запрашивает данные у сервера. Данных — относительно много, этот наш person содержит в себе его автобиографическое видео — 1 минута, 50 мегабайт.
Вот мы запустили всё это в производство, посмотрели метрики — тяжеловато, наш сервер перегружен. Перегружен он потому, что отдаёт данные со скоростью клиента; поэтому далёкие клиенты в Мексике, которых оказалось неожиданно много, удерживают соединение открытым очень долго, и наш COM-объект отжирает нужные другим ресурсы. Снижается степень параллелизма.
Что, Павел, ты будешь делать? Ссылаться на то, что заказчики — козлы, и никогда заранее не описывают все требования?
Ну ок, эффективность фермы — никакая. Если бы у тебя был REST, то ты, не трогая само приложение, спокойно бы начал с того, что развернул бы на исходном адресе reverse proxy, чтобы разгрузить свой бэк-енд. Не написав ни строчки кода, получил бы расшивание боттлнека на порядок.
Далее, проанализировав нагрузку, поставил бы локальный прокси в Мексике, а на исходном адресе нарулил бы правило "если клиент пришёл из такого-то IP диапазона, то перенаправь его на мексиканский гейт".
Теперь у клиентов раундтрип до точки входа не 1200мс, а 80мс.
Опять — не написав ни строчки кода, ты меняешь потоки данных, и масштабируешь приложение. Более того — тебе даже не надо обзванивать мексиканских клиентов и говорить им "пожалуйста, пропишите у себя в конфиге вот такой адрес сервера".
"Нечего перенаправлять" — это не значит "не нужно перенаправлять", а "тупой RPC неспособен перенаправить".
Я на голом HTTP могу изваять geo-redundancy и load-balancing. А что ты предложишь делать с RPC?
Далее, "пусть сервер разбирается, что modified, а что нет" — ты вот сядь, напиши сигнатуру метода. Это в теории всё кажется понятным. Если своего опыта работы с сетью нету — ты уж не стесняйся, поверь более опытным товарищам.
А на практике внезапно оказывается, что запилить хотя бы треть того, что в REST идёт из коробки, в RPC руки не доходят. Влаги в организме столько нету, сколько пота потребуется пролить.
Для начала тебе придётся сделать тип данных вариативным — чтобы можно было вернуть как person, так и "ничего".
Далее, тебе придётся добавить в person какой-то индикатор, который ты потом будешь использовать в условных запросах. И не только в person, а во все типы, которые ты собрался тащить к себе через RPC.
Сжатие — то же самое. Один сервер умеет сжатие, а другой — нет. То есть мало того, что клиент не обязан указывать свои предпочтения; сервер ещё и не обязан их выполнять.
То есть мы не можем просто выставить два метода GetPerson и GetPersonCompressed. У нас один метод возвращает либо person, либо "байтовый поток".
Что у нас со штатным маршалингом? Вкорзинку?
Ок, остаётся простой способ — делать свой велосипед поверх RPC. То есть приделываем метаданные — те самые "хидеры", которых в RPC нет — дату изменения контента или его тег, признак сжатия. Тащим данные в виде байтового потока.
Вытащив их в клиента, вручную выполняем маршаллинг в зависимости от того, какие флаги приехали в метаданных.
А потом заказчик говорит "а что, вы не можете сделать докачку частично загруженного person при обрыве соединения?", и ты начинаешь всё переписывать сначала — потому что теперь тебе нужен какой-то способ передать в GetPerson информацию о том, что "треть данных у меня уже есть, давай остальное", и опять расширять набор флагов. Потому что сервер по-прежнему не обязан уметь частичную закачку, и он может в ответ на такой запрос передать цельного пёрсона.

И на фоне этого делается вывод, что "ну, REST — это применение неудачной концепции за рамками изначальной задачи, бла-бла-бла". Да какая разница, кто для чего исходно предназначался. Мы же инженеры — нам важно то, какие результаты можем мы получить. Ай-яй-яй, атом изначально разлагали для получения оружия. А теперь его зачем-то применяют для выработки электричества. Ну давайте, вернёмся к основам! А электричество будем вырабатывать как деды завещали — бензиновым генератором.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Отредактировано 14.02.2020 5:57 Sinclair . Предыдущая версия . Еще …
Отредактировано 14.02.2020 5:47 Sinclair . Предыдущая версия .
Re[11]: REST: прохой\хороший интерфейс
От: Sinclair Россия https://github.com/evilguest/
Дата: 12.02.20 04:07
Оценка: 15 (1)
Здравствуйте, Sharov, Вы писали:

S>А что значит состояние сервера, значение регистров цпу + озу, бд?

Это значит, что одинаковый запрос может приводить к разным результатам. Технически — да, содержание регистров, RAM, HDD, и прочих локальных ресурсов.
S>Почему используется слово "представление", а не слово "часть" данных.
Потому, что речь не только о "проекции", но и о трансформации.
Самый простой пример — сервер возвращает "текущее время". Внутри оно хранится как, например, unixtime. Но клиент видит его как ISO 8601.
Более жизненный пример — ресурс "заказ в интернет-магазине" представлен на стороне сервера как содержимое десятка таблиц, а клиент видит его как единый JSON-документ. И модифицирует как единый JSON-документ.
Примерно такое же отличие, как между property и field в C#/Delphi: состояние объекта хранится в полях, но читать и изменять его можно только через свойства.
S>>И, с точки зрения Филдинга, REST — первичен, как абстрактная модель. HTTP 1.1 — это, с его точки зрения, всего лишь пример применения концепции REST к World Wide Web. (Глава 6.3).
S>Фундаментальнее скорее, ибо полиморфизм (get,post..) во весь рост, но вдохновлялся http.
В тексте диссертации прямым текстом написано, что при проектировании HTTP 1.1 применялся REST
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Отредактировано 12.02.2020 5:57 Sinclair . Предыдущая версия .
Re[14]: REST: прохой\хороший интерфейс
От: samius Япония http://sams-tricks.blogspot.com
Дата: 12.02.20 23:37
Оценка: 6 (1)
Здравствуйте, ·, Вы писали:

·>Здравствуйте, Sharov, Вы писали:


S>>Влезу. Ну, например, калькулятор, который на удаленной машине чего-то считает. rpc прямолинеен, а вот с rest придется попотеть. Вообще, как я понимаю, rest нужен, когда мы имеем дело

S>>с необходимостью CRUD чего-то. Если нам просто нужны чьи-то выч. ресурсы и время, без соотв. crud, то rpc вполне подойдет.
·>Калькулятор это stateless — скучно и тривиально, решается одинаково просто практически на чём угодно левой пяткой во сне. А REST это всё-таки Representational state transfer.

Есть таки ощущение неверной трактовки слова "state" в аббревиатуре REST. Речь вовсе не о том, как мы будем менять состояние на сервере, и будем ли вообще. Вот что пишет об этом Филдинг:

REST was originally referred to as the "HTTP object model," but that name would often lead to misinterpretation of it as the implementation model of an HTTP server. The name "Representational State Transfer" is intended to evoke an image of how a well-designed Web application behaves: a network of web pages (a virtual state-machine), where the user progresses through the application by selecting links (state transitions), resulting in the next page (representing the next state of the application) being transferred to the user and rendered for their use.


То есть, по-крайней мере название REST — это о том, как клиент хранит состояние сессии. Но, конечно, REST не ограничивается одной лишь этой идеей, в списке идей источников присутствует Remote Session.
Re[18]: REST: прохой\хороший интерфейс
От: Буравчик Россия  
Дата: 13.02.20 12:37
Оценка: 6 (1)
Здравствуйте, Sinclair, Вы писали:

S>Встречный вопрос — а что нам предлагает RPC?


Передачу ключей идемпотентности, как и REST. И нужно явно позаботиться об этом, как и в REST.

Интересно, что при проектировании приложения ты используешь анемик (ФП-стиль), но при проектировании API действуешь с точность до наоборот.
Рассматривая соседнюю тему о расчете надбавки, вероятно, в API появидсяся бы ресурс "рассчитать надбавку" (ок, просто "надбавка").
Но это и есть RPC-стиль, о котором я говорил выше. Работа от операций, а не от ресурсов.
Best regards, Буравчик
Re[3]: REST: прохой\хороший интерфейс
От: vsb Казахстан  
Дата: 31.01.20 14:17
Оценка: 4 (1)
Здравствуйте, ylem, Вы писали:

vsb>>1. Действия соответствуют семантике. GET возвращает, PUT кладёт, и тд. Кроме того соблюдается идемпотентность, т.е. можно вызывать GET или PUT сколько угодно раз с одними и теми же параметрами.


Y>Подскажите, пожалуйста, как правильный REST будет выглядеть для случая например:

Y>Есть модель объекта в обычном 3D пространстве и ее нужно сдвинуть на сколько-то в какую-то сторону.

Вычисляешь новые координаты и вызываешь PATCH /object/25 {"x": 123, "y": 456}.

Y>Если "сдвинуть" слишком просто, то чуть служнее: сплющить.


То же самое, вычисляешь новый размер и вызываешь PATCH.

Y>А "идемпотентность" тут как-то можно соблюсти?


Если подход с вычислением нового состояния на клиенте невозможно применить, очевидно, что никак. Вызываешь POST и забиваешь на идемпотентность. Правда что делать, когда тебе не пришёл положительный ответ на POST, уже никто не скажет. Повторять его небезопасно. Можно сказать юзеру, что произошла ошибка и сложить ручки. В случае PUT можно, например, попробовать повторить запрос. Если проблема была неперманентная (например перезагружали сервер или были проблемы с сетью), пользователь даже не заметит ничего.

Y>Если я неправильно смотрю на весь дизайн, то как правильно, при условии, что объект есть, и только штука с интерфейсом знает, как его правильно двигать и плющить.


Как вариант — создавать некий ID для изменения-транзакции и делать PUT этой транзакции. На сервере, соответственно, проверять, что эта транзакция уже не выполнялась (т.е. вести лог).

Но такой подход в любом случае в REST не очень укладывается. REST это штука специфичная и натягивать произвольное API на него невозможно. В этом его минус и причина непрактичности, на практике его все нарушают и творят что хотят, именуя по сути обычный RPC интерфейс REST-ом.
Re[3]: REST: прохой\хороший интерфейс
От: Буравчик Россия  
Дата: 31.01.20 15:42
Оценка: 4 (1)
Здравствуйте, ylem, Вы писали:

Y>А "идемпотентность" тут как-то можно соблюсти?


Передавать на сервер idempotency key.
На сервере проверять наличие поступивших ранее запросов с таким же ключом.
Best regards, Буравчик
Re[3]: REST: прохой\хороший интерфейс
От: Cyberax Марс  
Дата: 01.02.20 10:35
Оценка: 3 (1)
Здравствуйте, ylem, Вы писали:

Y>Если "сдвинуть" слишком просто, то чуть служнее: сплющить.

Y>А "идемпотентность" тут как-то можно соблюсти?
Можно. Например: "PUT /object/123123/move?deltaXMeters=33.5", — двигаем объект с ID=123123 на 33.5 метров. В результате получаем новый объект с ID=123124. К нему можно применять другие преобразования.
Sapienti sat!
Re[3]: REST: прохой\хороший интерфейс
От: scf  
Дата: 06.02.20 15:15
Оценка: 2 (1)
Здравствуйте, Буравчик, Вы писали:

Б>Все, что можно сделать в REST, можно и в RPC.

Б>Хотелось бы услышать список преимуществ REST перед RPC.

Для начала, что такое REST, без фанатизма и упоротости.
REST — это способ реализации RPC, опирающийся на стандарты и best practices для HTTP и связанных rfc, и способ формирования ендпоинтов RPC на основе концепции ресурсов.

Первое и главное, REST сделан для людей, не для машин. Все знают REST, т.е. заранее известно:
— как передавать обязательные и необязательные параметры, как получить и распарсить результат
— какие вызовы меняют состояние, а какие просто возвращают данные
— какие вызовы идемпотентны, а какие создают новые сущности
— как возвращаются ошибки, какие ошибки retryable, какие non-retryable
— как делается аутентификация и авторизация
— как ориентироваться в API

Второе, иерархичность. Понятия "ресурс", CRUD над ресурсом и вложенные ресурсы в урле оказались Хорошей Идеей. Удобной для человека, удобной для развития апи, когда разные версии можно держать на одном днс с разными префиксами. Иерархичные ресурсы также очень удобно обмазывать авторизацией, разрешая или запрещая доступ по префиксам урлов.

Третье, популярность и доступнсть. Есть огромное количество тулов для отправки REST запросов, от браузера и curl до специализированных приложений.

Четвертое, стандартность и расширяемость. Если вдруг захочется странного, часто можно раскопать RFC с нужным функционалом и не изобретать своё решение.
Re: REST: прохой\хороший интерфейс
От: vsb Казахстан  
Дата: 30.01.20 06:58
Оценка: :)
1. Действия соответствуют семантике. GET возвращает, PUT кладёт, и тд. Кроме того соблюдается идемпотентность, т.е. можно вызывать GET или PUT сколько угодно раз с одними и теми же параметрами.

2. URL структурированный типа /users/123 а не /user?id=123.

3. Выдаются правильные заголовки для кеширования.
Re: REST: прохой\хороший интерфейс
От: Буравчик Россия  
Дата: 30.01.20 11:08
Оценка: +1
Здравствуйте, a.v.v, Вы писали:

AVV>вот и задумался а что такое этот хороший интерфейс, у самого есть конечно мысли но какие то они не очень убедительные


Мне кажется, что самое важное:
— простота
— консистентность (согласованность)

Вот статья об этом:
https://habr.com/ru/company/oleg-bunin/blog/358600/
Best regards, Буравчик
Отредактировано 30.01.2020 11:08 Буравчик . Предыдущая версия .
Re[7]: REST: прохой\хороший интерфейс
От: Cyberax Марс  
Дата: 04.02.20 02:20
Оценка: -1
Здравствуйте, Doc, Вы писали:

Doc>>>В этом случае следующий повторный PUT добавит еще 1 объект с 123125 итд. Насколько я понимаю это будет противоречить логике, возлагаемой на PUT.

C>>Это вполне соответствует PUT/PATCH.
Doc>Как? Ведь если повторить PUT с тем же параметрами, то он не должен изменить состояние системы.
Ну так оно и не изменится. Старые объекты все останутся как есть, новый объект будет себе просто так висеть и никого не трогать.

Doc>А тут получаем новый объект. То, что вы описали больше подходит под POST (веть по сути создает новый объект, хоть и на базе старого).

Я бы не заморачивался о тонкостях между PUT/POST/PATCH.
Sapienti sat!
Re[10]: REST: прохой\хороший интерфейс
От: Pavel Dvorkin Россия  
Дата: 12.02.20 15:31
Оценка: +1
Здравствуйте, Sinclair, Вы писали:

S>Вот ровно всё — мимо.


Думаю, что все же не все

S>1. Во-первых, проблемы не у меня, а у RPC. Это ущербная концепция, плохо применимая в сетевых реалиях.


Ну это обсуждать не стоит. Она есть, она работает.

S>2. Во-вторых, никакой "психологии" тут нет. Есть банальный прагматизм, выработанный многолетней практикой.


На основании существующих рецептов и идей. Которые определяются в значительной мере этой практикой. Попробуй от нее отрешиться и подумай — если бы тебе дали возможность спроектировать протокол заново, ты бы точно сделал HTTP ? Сейчас, зная все, что есть, а не 20 веке.

S>А сама концепция кэширования и delta-encoding выходит далеко за рамки HTTP.

PD>>Я не буду, конечно, утверждать, что клиент РБД связывается с ней по именно по RPC. Там внизу скорее всего иначе. Но суть от этого не меняется.
PD>>Запросил ты что-то с помощью SELECT и что ? Кто там не изменился и что должно возвращаться ? Нет такого понятия — не изменился. Просил — получи, а потом сам и разбирайся, что там изменилось, а что нет.
S>Ну, так это-то и плохо. Качаем терабайт данных для того, чтобы заменить одну строчку. Павел, ты уверен, что это — лучше, чем HTTP?

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


S>Если тебе интересно, как сделать change tracking в RDBMS — обращайся. Я участвую в топиках на эту тему в соответствующем форуме в среднем ежегодно


Раз в год ?

Спасибо, понадобится — обращусь.

S>И опять ровно всё — мимо.

S>Сначала для интерфейса со "сложным серверным кодом" начали применять RPC. Потом — RMI. Применение HTTP для этого возникло существенно позже. И, естественно, сначала усилия были вложены в противоположную сторону — люди взяли из HTTP ровно один глагол (самый бесполезный) и завернули RPC/RMI в XML over HTTP.

Верно, позже. Но я вовсе не сравнивал в этом плане RPC и HTTP. Я просто повторяю — HTTP был не для сложных задач сделан, а для (в основном) статических сайтов, ну , может, с примесью CGI. Не было он сделан как протокол для сложных приложений, которых просто тогда не только не было, а и представить себе никто не мог. Ну а потом начали его натягивать на эти сложные приложения, в итоге имеем что имеем.

По сути, глаголы HTTP — это CRUD. Не совсем точно, конечно, но в основном. Вот и делается попытка натянуть на CRUD все действия, которые нужны в приложении. Между тем RPC от всего этого свободен. Это просто набор функций/методов, которые делают то, что автору нужно. Как, впрочем, и наборы функций/методов в любых библиотеках и их пакетах/неймспейсах/классах.

Вот ответь мне на такой вопрос. Есть некое действие, которое нужно выполнить. Суть его заключается в добавлении чего-то куда-то на сервере. Однако если при этом возникнет ситуация X, то необходимо на сервере, вместо этого добавления, произвести изменения других существующих там данных или их удаление. Данные для этих изменений/удалений в запросе не передаются, они образуются в результате обработки запроса на добавление и возникновения ситуации X.

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

HTTP — какой глагол употребим ?

S>RPC тут оказался мимо тазика — во всех его инкарнациях.


RPC, с твоего разрешения, лежит под DCOM/OLE (ты это должен знать), а там гораздо более сложная логика, чем в бизнес-приложениях. Убери RPC — и Windows больше нет.
With best regards
Pavel Dvorkin
Отредактировано 12.02.2020 16:12 Pavel Dvorkin . Предыдущая версия .
Re[11]: REST: прохой\хороший интерфейс
От: Sinclair Россия https://github.com/evilguest/
Дата: 12.02.20 17:27
Оценка: +1
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>Ну это обсуждать не стоит. Она есть, она работает.
Неа, не работает. Возникает иллюзия работы. Которая продолжается ровно до первого залетевшего дятла.
Павел, не надо спорить на ровном месте — поверь опыту людей, которые видели и эксплуатировали всякие разные виды API.

PD>На основании существующих рецептов и идей. Которые определяются в значительной мере этой практикой. Попробуй от нее отрешиться и подумай — если бы тебе дали возможность спроектировать протокол заново, ты бы точно сделал HTTP ? Сейчас, зная все, что есть, а не 20 веке.

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

PD>А вот тут как ситуация, которую я в свое время программировал, с использованием thrift. Сервер имеет данные, и по ходу действия к ним кое-что может добавить, а иногда удаляет их все и начинает их вырабатывать с начала. До терабайтов там, правда, дело не доходило, но не так уж мало. Естественно, я не делал перекачки всего, брал инкрементально.

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

PD>Раз в год ?

Ну да, сейчас вообще трафик профильных форумов низкий.
PD>Верно, позже. Но я вовсе не сравнивал в этом плане RPC и HTTP. Я просто повторяю — HTTP был не для сложных задач сделан, а для (в основном) статических сайтов, ну , может, с примесью CGI. Не было он сделан как протокол для сложных приложений, которых просто тогда не только не было, а и представить себе никто не мог. Ну а потом начали его натягивать на эти сложные приложения, в итоге имеем что имеем.
В том-то и дело, что начали "натягивать" его уже после того, как попробовали другие подходы. Внезапно оказалось, что он гораздо лучше подходит для сложных приложений, чем любая корба, не говоря уже о SOAP.

PD>По сути, глаголы HTTP — это CRUD. Не совсем точно, конечно, но в основном.

Именно, что совсем.
PD>Вот и делается попытка натянуть на CRUD все действия, которые нужны в приложении. Между тем RPC от всего этого свободен. Это просто набор функций/методов, которые делают то, что автору нужно. Как, впрочем, и наборы функций/методов в любых библиотеках и их пакетах/неймспейсах/классах.
))
Павел, очень, очень советую почитать литературу. Ссылка на бесплатную книжку приведена прямо в этом топике. "Свобода" RPC означает, по большому счёту, свободу писать некорректные и неоптимизируемые протоколы.

PD>Вот ответь мне на такой вопрос. Есть некое действие, которое нужно выполнить. Суть его заключается в добавлении чего-то куда-то на сервере. Однако если при этом возникнет ситуация X, то необходимо на сервере, вместо этого добавления, произвести изменения других существующих там данных или их удаление. Данные для этих изменений/удалений в запросе не передаются, они образуются в результате обработки запроса на добавление и возникновения ситуации X.


PD>С RPC все просто — назови функцию как хочешь, передай в ней данные, а там она пусть делает , что там надо, в соответствии с логикой действий. Кстати, обрати внимание вот на что. Довольно странно было бы представить себе дискуссию, в которой обсуждался бы правильный порядок параметров методов. Да, какие-то писаные или неписаные правила есть, вроде того, что handle передается обычно первым параметром, но в остальном — да нечего тут обсуждать, что надо, то и передаем, в какой форме надо, в такой и передаем. А тут целая дискуссия о том, в сущности, как правильно параметры передавать.

Нет. Дискуссия о том, какие параметры передавать. И логика, привычная разработчикам локальных программ, тут не работает. Это у вас вызов стоит наносекунды, а его обработка — миллисекунды. И он всегда заканчивается детерминированным результатом. А в сети вызов может занимать секунды, а его обработка — миллисекунды. И никогда нет гарантии узнать, завершился ли вызов успешно, или нет.

PD>HTTP — какой глагол употребим ?

С точки зрения HTTP, совершенно неважно, что там происходит "на сервере". Важно то, как мы это представляем клиенту. Representational State Transfer. Если клиенту выставляется такая модель ресурсов, что при применении этого действия к модели добавляется новый ресурс, то делаем через PUT.
На всякий случай поясню, что такие вопросы обсуждать бессмысленно. Конструктивную беседу можно вести только в рамках более-менее очерченной задачи.
Придумай задачу, для которой тебе кажется естественным некий RPC-API (можешь сразу и набросать его черновик), а REST-API вызывает затруднения. Я покажу, как сделать REST для этой задачи, и можно будет сравнить достоинства и недостатки.

PD>RPC, с твоего разрешения, лежит под DCOM/OLE (ты это должен знать), а там гораздо более сложная логика, чем в бизнес-приложениях. Убери RPC — и Windows больше нет.

Я вас умоляю. DCOM/OLE работает в тепличных условиях локальной машины. В нём ситуация "не удалось доставить результат вызова обратно" — редкость. И когда она случается, результат лечат перезагрузкой машины.
Использовать DCOM через океан — упаси байт! Представь себе приложение резервирования авиабилетов, написанное на DCOM. Или хотя бы онлайн-регистрации. Нафиг-нафиг.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[12]: REST: прохой\хороший интерфейс
От: Sharov Россия  
Дата: 12.02.20 18:12
Оценка: +1
Здравствуйте, Sinclair, Вы писали:


S>На всякий случай поясню, что такие вопросы обсуждать бессмысленно. Конструктивную беседу можно вести только в рамках более-менее очерченной задачи.

S>Придумай задачу, для которой тебе кажется естественным некий RPC-API (можешь сразу и набросать его черновик), а REST-API вызывает затруднения. Я покажу, как сделать REST для этой задачи, и можно будет сравнить достоинства и недостатки.

Влезу. Ну, например, калькулятор, который на удаленной машине чего-то считает. rpc прямолинеен, а вот с rest придется попотеть. Вообще, как я понимаю, rest нужен, когда мы имеем дело
с необходимостью CRUD чего-то. Если нам просто нужны чьи-то выч. ресурсы и время, без соотв. crud, то rpc вполне подойдет.
Кодом людям нужно помогать!
Re[16]: REST: прохой\хороший интерфейс
От: samius Япония http://sams-tricks.blogspot.com
Дата: 13.02.20 09:56
Оценка: +1
Здравствуйте, ·, Вы писали:

·>Здравствуйте, samius, Вы писали:


S>>>>Влезу. Ну, например, калькулятор, который на удаленной машине чего-то считает. rpc прямолинеен, а вот с rest придется попотеть. Вообще, как я понимаю, rest нужен, когда мы имеем дело

·>...
S>>То есть, по-крайней мере название REST — это о том, как клиент хранит состояние сессии. Но, конечно, REST не ограничивается одной лишь этой идеей, в списке идей источников присутствует Remote Session.
·>Не совсем понятно к чему ты это говоришь. Какое состояние сессии в рассматриваемом примере калькулятора? Ведь тут не нужно никаких сессий, тривиальный запрос-ответ, никакого состояния репрезентить не надо.

Я не о сессиях. Я о том, что именно за состояние фигурирует в названии REST. В духе того, что я процитировал из работы Филдинга, REST калькулятор вовсе не stateless. Когда мы говорим о состоянии в REST, то это не состояние, которое вынужден хранить сервер. Это состояние приложения в терминах машины состояний, по которым водят пользователя. Например:
Состояние редактирования выражения <=> состояние просмотра результата.
Re[16]: REST: прохой\хороший интерфейс
От: Sharov Россия  
Дата: 13.02.20 14:52
Оценка: +1
Здравствуйте, Sinclair, Вы писали:

S>Может быть, это и хорошо? Системы проектируют под реальные требования, а не под абстрактные капризы.

S>Если в вашей задаче "параметром" ресурса становится слишком длинная строка — да, придётся приседать. Но это бывает а) редко, б) обходится нетрудно.

Трабования имеют св-во менятся, зачастаю неожиданным и непредсказуемым образом.

S>Вы неправильно понимаете rest. Этот ресурс, конечно же, есть, и мы ничего не "ломаем".

S>REST совершенно не обязывает вас ограничиваться только "реально существующими" ресурсами, или даже конечным их списком.
S>Вот, к примеру, таблица умножения — совершенно необязательно хранить её на сервере. Можно её вычислять — но клиенту-то всё равно!
S>У него создаётся иллюзия того, что на сервере "хранится" практически бесконечная таблица умножения. Зачем ему отличать "вычисленные" ресурсы от "реальных"?

В целом, Вы правы, так думать можно. Но, думается, когда Филдинг все это дизайнил речь шла о конретных, конечных ресурсах, типа стат. html страничек. Т.е. что-то сущ. и конечное.
Все можно положить на rest, но не всегда нужно.

S>Можно ссылку на эти рекомендации? Может, я что-то упустил.


Помню где-то читал, и недавно, но найти не могу.
Кодом людям нужно помогать!
Re[24]: REST: прохой\хороший интерфейс
От: Pavel Dvorkin Россия  
Дата: 14.02.20 08:16
Оценка: :)
Здравствуйте, Sinclair, Вы писали:

S>Ну да. И ждём ещё 30 лет, пока для твоего нового протокола появятся nginx и CDN-провайдеры. Делов-то.


И ждем еще 10 лет, пока эта Ваша новая Windows NT 3.1 станет такой же удобной для пользователя, как существующая Windows 95. Ну и что, что эта Windows 95 архитектурное убожество. Зато <аргументы за Windows 95 против Windows NT 3.1 можешь сам написать>

Я разве говорю, что нужно сейчас везде HTTP заменить на RPC ?

Я говорю о том, как это нужно было бы сделать "как следует".

А то, что мы не дождемся Windows XP/7/10 — это и так ясно.

Увы.
With best regards
Pavel Dvorkin
REST: прохой\хороший интерфейс
От: a.v.v Россия  
Дата: 30.01.20 00:46
Оценка:
Во многих вакансиях появилось требование звучащее как — уметь проектировать хороший rest интерфейс
вот и задумался а что такое этот хороший интерфейс, у самого есть конечно мысли но какие то они не очень убедительные

вот хотел бы послушать коллективное бессознательное

заранее благодарю
Re[2]: REST: прохой\хороший интерфейс
От: ylem  
Дата: 31.01.20 13:41
Оценка:
vsb>1. Действия соответствуют семантике. GET возвращает, PUT кладёт, и тд. Кроме того соблюдается идемпотентность, т.е. можно вызывать GET или PUT сколько угодно раз с одними и теми же параметрами.

Подскажите, пожалуйста, как правильный REST будет выглядеть для случая например:
Есть модель объекта в обычном 3D пространстве и ее нужно сдвинуть на сколько-то в какую-то сторону.
Если "сдвинуть" слишком просто, то чуть служнее: сплющить.
А "идемпотентность" тут как-то можно соблюсти?

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

Если расскажете, большое спасибо.
Если не расскажите, просто спасибо, что дочитали
Re[4]: REST: прохой\хороший интерфейс
От: Doc Россия http://andrey.moveax.ru
Дата: 03.02.20 04:29
Оценка:
Здравствуйте, Cyberax, Вы писали:

C>Можно. Например: "PUT /object/123123/move?deltaXMeters=33.5", — двигаем объект с ID=123123 на 33.5 метров. В результате получаем новый объект с ID=123124. К нему можно применять другие преобразования.


В этом случае следующий повторный PUT добавит еще 1 объект с 123125 итд. Насколько я понимаю это будет противоречить логике, возлагаемой на PUT. Да и копировать объект на каждый чих занятие так себе.
Re[5]: REST: прохой\хороший интерфейс
От: Cyberax Марс  
Дата: 04.02.20 01:59
Оценка:
Здравствуйте, Doc, Вы писали:

C>>Можно. Например: "PUT /object/123123/move?deltaXMeters=33.5", — двигаем объект с ID=123123 на 33.5 метров. В результате получаем новый объект с ID=123124. К нему можно применять другие преобразования.

Doc>В этом случае следующий повторный PUT добавит еще 1 объект с 123125 итд. Насколько я понимаю это будет противоречить логике, возлагаемой на PUT.
Это вполне соответствует PUT/PATCH.

Doc>Да и копировать объект на каждый чих занятие так себе.

Целиком зависит от задачи.

Если копирование неприемлимо — можно использовать ключи идемпотентности.
Sapienti sat!
Re[6]: REST: прохой\хороший интерфейс
От: Doc Россия http://andrey.moveax.ru
Дата: 04.02.20 02:16
Оценка:
Здравствуйте, Cyberax, Вы писали:

Doc>>В этом случае следующий повторный PUT добавит еще 1 объект с 123125 итд. Насколько я понимаю это будет противоречить логике, возлагаемой на PUT.

C>Это вполне соответствует PUT/PATCH.

Как? Ведь если повторить PUT с тем же параметрами, то он не должен изменить состояние системы. А тут получаем новый объект. То, что вы описали больше подходит под POST (веть по сути создает новый объект, хоть и на базе старого).
Re[8]: REST: прохой\хороший интерфейс
От: Doc Россия http://andrey.moveax.ru
Дата: 04.02.20 02:36
Оценка:
Здравствуйте, Cyberax, Вы писали:

C>Я бы не заморачивался о тонкостях между PUT/POST/PATCH.


И при этом спорите что это не POST, а PUT. Ну да после такого заявления вопросов больше нет
Re[9]: REST: прохой\хороший интерфейс
От: Cyberax Марс  
Дата: 04.02.20 04:24
Оценка:
Здравствуйте, Doc, Вы писали:

C>>Я бы не заморачивался о тонкостях между PUT/POST/PATCH.

Doc>И при этом спорите что это не POST, а PUT. Ну да после такого заявления вопросов больше нет
Не, ну я не адепт REST-о-строя. У меня в API большинство методов тупо POST, включая создание и редактирование. В новых сервисах вообще на него забил и использую Twirp ( https://github.com/twitchtv/twirp/ ).

При дизайне API гораздо важнее продумывать стратегии обеспечения идемпотентности, авторизации, retries и т.п.
Sapienti sat!
Re[7]: REST: прохой\хороший интерфейс
От: Sinclair Россия https://github.com/evilguest/
Дата: 04.02.20 09:18
Оценка:
Здравствуйте, Doc, Вы писали:

Doc>Как? Ведь если повторить PUT с тем же параметрами, то он не должен изменить состояние системы. А тут получаем новый объект. То, что вы описали больше подходит под POST (веть по сути создает новый объект, хоть и на базе старого).

Вот тут начинает играть роль тот вопрос, который я задавал в параллельной подветке: живёт ли объект сам по себе, или является частью сцены.
Если сам по себе — то ничего страшного, у нас получилось 2 (3, и т.д.) "копии" объекта. Т.е. имеем что-то типа набора версий, которые существуют более-менее независимо. "Сломать" объект нельзя, всегда можно вернуться к "старому" id и применить к нему другую трансформацию.
А вот если у нас есть сцена, то уже вопрос — как себя будет вести она при таких трансформациях. Очевидно, что она не должна забиваться репликами объектов. С другой стороны, даже такая архитектура ничему не противоречит — сцена может определяться "тегом", который навешивается на какие-то версии объектов. Модификация будет переносить тег со "старого" объекта на "новый" — либо автоматически, либо вручную.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[10]: REST: прохой\хороший интерфейс
От: Sinclair Россия https://github.com/evilguest/
Дата: 04.02.20 09:23
Оценка:
Здравствуйте, Cyberax, Вы писали:

C>При дизайне API гораздо важнее продумывать стратегии обеспечения идемпотентности, авторизации, retries и т.п.

Очень странно говорить о стратегиях обеспечения идемпотентности и retries, при этом игнорируя глаголы HTTP.

Понятно, что в общем случае "просто выбрать PUT" недостаточно; я вот прямо сейчас наблюдаю чудеса во вполне РЕСТ-овом API от Microsoft (https://docs.microsoft.com/en-us/partner-center/develop/partner-center-rest-api-reference), где парни ухитрились на ровном месте сделать невозможным предотвращение двоящихся или потерянных заказов.
Я так понимаю — как раз потому, что они не очень хорошо понимали, что такое REST, и задумывались о "стратегиях, которые гораздо важнее". Идемпотентность в старом order api они обеспечивали через custom header "Request-ID", а в новом shopping cart команде просто об этом хидере не рассказали.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[8]: REST: прохой\хороший интерфейс
От: Mihas  
Дата: 04.02.20 10:08
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>А вот если у нас есть сцена, то уже вопрос — как себя будет вести она при таких трансформациях. Очевидно, что она не должна забиваться репликами объектов.

Сцена может иметь свою версию, представляющую срез версий ее объектов на момент времени.
Re[9]: REST: прохой\хороший интерфейс
От: Sinclair Россия https://github.com/evilguest/
Дата: 04.02.20 12:35
Оценка:
Здравствуйте, Mihas, Вы писали:

S>>А вот если у нас есть сцена, то уже вопрос — как себя будет вести она при таких трансформациях. Очевидно, что она не должна забиваться репликами объектов.

M>Сцена может иметь свою версию, представляющую срез версий ее объектов на момент времени.
Опять: всё зависит от неизвестных нам требований. "Момент времени" — штука условная. Может запросто оказаться, что интересная нам версия сцены состоит из объекта X в момент T0, и объекта Y на момент T1, при этом X-в-момент-T1 нам не нужен. В общем, это всё примерно как задача "а спроектируйте мне иерархию классов, описывающую квадрат, прямоугольник, круг, и эллипс".
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[8]: REST: прохой\хороший интерфейс
От: Doc Россия http://andrey.moveax.ru
Дата: 05.02.20 02:59
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>Если сам по себе — то ничего страшного, у нас получилось 2 (3, и т.д.) "копии" объекта. Т.е. имеем что-то типа набора версий, которые существуют более-менее независимо. "Сломать" объект нельзя, всегда можно вернуться к "старому" id и применить к нему другую трансформацию.


Но ведь по определению PUT при существующем ID объекта, он должен модифицировать объект. Поэтому такой подход для меня выглядит странно.
Я понимаю, что тут реально можно натянуть сову на глобус, оперируя поведением BL, но это уже рассуждение об абстрактной BL. Тут можно что угодно нафантазировать (нам же ее не имплементировать и не поддерживать )
Re[12]: REST: прохой\хороший интерфейс
От: Sinclair Россия https://github.com/evilguest/
Дата: 05.02.20 06:26
Оценка:
Здравствуйте, Cyberax, Вы писали:

C>Ну вот им как раз нужно было думать не о глаголах, а об API. Если есть ключ идемпотентности — надо явно вносить его в тело запроса, а не играться с заголовками.

Если бы они думали о глаголах, то Create an Order выполнялось бы через PUT.
И никакого "ключа идемпотентности" бы не потребовалось. Но там работают ваши единомышленники, и они решили, что "а захреначу как я всё через POST".

Потом пришло второе поколение, которое про REST знало ещё меньше. Поэтому новый API, построенный на Create Cart / Checkout Cart, в принципе не позволяет добиться идемпотентности. При определённом стечении событий, можно ухитриться купить товар, и потерять об этом информацию.

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

Мне кажется, что вы просто не разобрались с REST. Самовыдуманные хидеры в нём не нужны.
С ошибками — да, одного способа нет.
Тем не менее, есть вполне нормальные решения на уровне договорённостей конкретного API: возвращаем структурированный JSON, в котором есть как код ошибки, так и сообщение, локализованное с учётом предпочтений клиента.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[9]: REST: прохой\хороший интерфейс
От: Sinclair Россия https://github.com/evilguest/
Дата: 05.02.20 06:39
Оценка:
Здравствуйте, Doc, Вы писали:

Doc>Но ведь по определению PUT при существующем ID объекта, он должен модифицировать объект. Поэтому такой подход для меня выглядит странно.

Ок, тут я несколько скомкал изложение. Вы правы — делать PUT, который самопроизвольно порождает новые объекты — плохо.
Делаем примерно так:
1. Внутрь объекта спрятана его версия. Когда мы делаем PUT, мы делаем инкремент известной нам версии на единичку. На сервере мы проверяем — выделяется три случая:
— версия на сервере N, пришла версия N+1 — сохраняем, 200 OK
— версия на сервере N, пришла версия N, контент совпадает — отдаём 200 Ok (idempotence)
— версия на сервере N, пришла версия N, контент не совпадает, либо пришла любая другая версия — отдаём 409 Conflict.
При этом старые версии объекта могут быть независимо доступны для чтения через отдельные адреса.
2. Версия объекта является частью его URL. Тогда редактирование делается при помощи POST, и каждый POST порождает новую версию где-то "рядом" с оригиналом.
Мы имеем право возвращать не новый URL каждый раз, а в случае совпадения с какой-либо из существующих версий возвращать её URL. Тогда мы заодно получаем идемпотентность — многократный POST с одним и тем же body будет возвращать один и тот же URL
Doc>Я понимаю, что тут реально можно натянуть сову на глобус, оперируя поведением BL, но это уже рассуждение об абстрактной BL. Тут можно что угодно нафантазировать (нам же ее не имплементировать и не поддерживать )
Снова возвращаемся к вопросу о требованиях. Без них решительно невозможно сравнивать характеристики разных решений, и всё упирается в "я не люблю глаголы за пределами GET и POST" или "я не люблю искусственные ключи идемпотентности".
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[13]: REST: прохой\хороший интерфейс
От: Cyberax Марс  
Дата: 05.02.20 07:47
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>Если бы они думали о глаголах, то Create an Order выполнялось бы через PUT.

S>И никакого "ключа идемпотентности" бы не потребовалось. Но там работают ваши единомышленники, и они решили, что "а захреначу как я всё через POST".
АБСОЛЮТНО И В КОРНЕ <b>НЕВЕРНО</b>!

Сам по себе PUT никоим образом не спасёт от двойного создания объекта. Просто теряем сетевое соединение при ответе и клиент получает что-нибудь типа 509 Gateway Error и упс. Всё что он может — повторить запрос, который может создать объект заново.

В REST конкретно все PUT/POST/GET/whatever — это чисто декорация, простейший вариант документации.

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

S>Мне кажется, что вы просто не разобрались с REST.
LOL.

S>Самовыдуманные хидеры в нём не нужны.

Ну вот тут же уже примеры с Request Id были.

S>С ошибками — да, одного способа нет.

S>Тем не менее, есть вполне нормальные решения на уровне договорённостей конкретного API: возвращаем структурированный JSON, в котором есть как код ошибки, так и сообщение, локализованное с учётом предпочтений клиента.
А ещё есть ответы с ошибками от load balancer'а в теле вместо ошибки. Или некоторые API, которые используют строку ответа HTTP.

Так же добавляются кривые стандарты (Swagger/OpenAPI) и получаем полное бинго.
Sapienti sat!
Re[14]: REST: прохой\хороший интерфейс
От: Sinclair Россия https://github.com/evilguest/
Дата: 05.02.20 11:58
Оценка:
Здравствуйте, Cyberax, Вы писали:
C>Сам по себе PUT никоим образом не спасёт от двойного создания объекта.
C>Просто теряем сетевое соединение при ответе и клиент получает что-нибудь типа 509 Gateway Error и упс. Всё что он может — повторить запрос, который может создать объект заново.
Совершенно верно. Вот тут-то и спасает идемпотентность PUT. Что именно вам непонятно?
Если мы получили 5xx, то у нас есть два варианта вернуться к синхронности:
1. Продолжать долбить тот же PUT, до получения однозначности: либо 4xx, который означает что создание точно сфейлилось, либо 2хх, который означает, что создание точно удалось.
2. Попробовать выполнять GET на тот же адрес, до получения однозначности: либо 200 Ok (возможно, с последующей проверкой, что контент — тот, что мы ожидаем), либо 404.

Заметьте, всё ещё никаких кастомных хидеров или искусственных ключей идемпотентности.

C>В REST конкретно все PUT/POST/GET/whatever — это чисто декорация, простейший вариант документации.

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

S>>Мне кажется, что вы просто не разобрались с REST.

C>LOL.
Пока что впечатление сохраняется — судя по вашим комментариям про PUT и 509 Gateway Error.

C>Ну вот тут же уже примеры с Request Id были.

Где? В примере про злоупотребление POST там, где нужно PUT?

C>А ещё есть ответы с ошибками от load balancer'а в теле вместо ошибки. Или некоторые API, которые используют строку ответа HTTP.

C>Так же добавляются кривые стандарты (Swagger/OpenAPI) и получаем полное бинго.
Это не вина REST как такового. REST закладывает достаточно основ для того, чтобы можно было отличить сбой от успеха, и retyable error от fatal error.
Как минимальная база — ок. Дальнейшие улучшения, как и все остальные улучшения, требуют дизайна. Строка ответа HTTP — это, скорее всего, плохой дизайн. Если он действительно плохой (а я вполне могу себе представить задачу, где он вполне Ок), то его авторы бы навелосипедили плохой дизайн и в любом другом подходе к проектированию API.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[15]: REST: прохой\хороший интерфейс
От: AndrewJD США  
Дата: 05.02.20 17:18
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>1. Продолжать долбить тот же PUT, до получения однозначности: либо 4xx, который означает что создание точно сфейлилось, либо 2хх, который означает, что создание точно удалось.

Так сервер уже вернул 2хх, а клиент получил 5хх. Как это разрулить без ключа?
"For every complex problem, there is a solution that is simple, neat,
and wrong."
Re[16]: REST: прохой\хороший интерфейс
От: Sinclair Россия https://github.com/evilguest/
Дата: 06.02.20 02:51
Оценка:
Здравствуйте, AndrewJD, Вы писали:

AJD>Здравствуйте, Sinclair, Вы писали:


S>>1. Продолжать долбить тот же PUT, до получения однозначности: либо 4xx, который означает что создание точно сфейлилось, либо 2хх, который означает, что создание точно удалось.

AJD>Так сервер уже вернул 2хх, а клиент получил 5хх. Как это разрулить без ключа?
Продолжать долбить тот же PUT, до получения однозначности: либо 4xx, который означает что создание точно сфейлилось, либо 2хх, который означает, что создание точно удалось.
Ключом в данном случае выступает адрес объекта. Главное слово: идемпотентность. Какой именно сценарий вам непонятен?
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re: REST: прохой\хороший интерфейс
От: · Великобритания  
Дата: 06.02.20 12:38
Оценка:
Здравствуйте, a.v.v, Вы писали:

AVV>Во многих вакансиях появилось требование звучащее как — уметь проектировать хороший rest интерфейс

AVV>вот и задумался а что такое этот хороший интерфейс, у самого есть конечно мысли но какие то они не очень убедительные
Некоторые детали уже рассказали, попробую сформулировать общую философию.
Надо осознать, что REST это не простой RPC между клиентом и сервером в локалке, а протокол взаимодействия распределённых гетерогенных систем в условиях дикого интернета.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[2]: REST: прохой\хороший интерфейс
От: Буравчик Россия  
Дата: 06.02.20 14:36
Оценка:
Здравствуйте, ·, Вы писали:

·>Здравствуйте, a.v.v, Вы писали:


AVV>>Во многих вакансиях появилось требование звучащее как — уметь проектировать хороший rest интерфейс

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

Все, что можно сделать в REST, можно и в RPC.
Хотелось бы услышать список преимуществ REST перед RPC.

Основное различие — REST оперирует ресурсами, а RPC — операциями. Но при проектировании обычно так: У нас есть 10 операций, давайте натянем их на REST (спроектируем ресурсы, применим к ним глаголы). Потом в документации напишем, чтобы выполнить операцию 1 — работаем с такими-то ресурсами, операцию 2 — с такими-то.

В RCP ничего этого не надо — есть операция, есть вход, есть выход.
Best regards, Буравчик
Re[3]: REST: прохой\хороший интерфейс
От: · Великобритания  
Дата: 06.02.20 15:04
Оценка:
Здравствуйте, Буравчик, Вы писали:

Б>Все, что можно сделать в REST, можно и в RPC.

Тут дело не в том, что можно сделать, а что нельзя. Это примерно то же отличие, как в стилях программирования. Скажем, всё что умеет функциональное программирование можно сделать процедурно. Но отличие-то есть!

Б>Хотелось бы услышать список преимуществ REST перед RPC.

Суть в том, что REST акцентирует внимание на такие делали, которые RPC просто игнорирует и которые больно кусают, но потом, и только если что-то пошло немного не так.

Б>Основное различие — REST оперирует ресурсами, а RPC — операциями. Но при проектировании обычно так: У нас есть 10 операций, давайте натянем их на REST (спроектируем ресурсы, применим к ним глаголы). Потом в документации напишем, чтобы выполнить операцию 1 — работаем с такими-то ресурсами, операцию 2 — с такими-то.

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

Б>В RCP ничего этого не надо — есть операция, есть вход, есть выход.

Угу. А если связь оборвалась — что выход? И что результат? И как об этом узнать?
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[17]: REST: прохой\хороший интерфейс
От: Ватакуси Россия  
Дата: 07.02.20 09:08
Оценка:
S>>>1. Продолжать долбить тот же PUT, до получения однозначности: либо 4xx, который означает что создание точно сфейлилось, либо 2хх, который означает, что создание точно удалось.
AJD>>Так сервер уже вернул 2хх, а клиент получил 5хх. Как это разрулить без ключа?
S>Продолжать долбить тот же PUT, до получения однозначности: либо 4xx, который означает что создание точно сфейлилось, либо 2хх, который означает, что создание точно удалось.
S>Ключом в данном случае выступает адрес объекта. Главное слово: идемпотентность. Какой именно сценарий вам непонятен?

И если одназночность так и не пришла, валить сервер DDOS-ом?
Все будет Украина!
Re[18]: REST: прохой\хороший интерфейс
От: Sharov Россия  
Дата: 07.02.20 11:00
Оценка:
Здравствуйте, Ватакуси, Вы писали:


В>И если одназночность так и не пришла, валить сервер DDOS-ом?


exponential back-off какой-нибудь...
Кодом людям нужно помогать!
Re[4]: интересное наблюдение
От: Sharov Россия  
Дата: 07.02.20 11:18
Оценка:
Здравствуйте, Sinclair, Вы писали:

Б>>Основное различие — REST оперирует ресурсами, а RPC — операциями.

S>REST оперирует состоянием. Самый простой пример: RPC говорит "включить свет", а REST говорит "свет должен стать включенным".

А вот это интересно -- у нас тут по образу и подобию происходит противопоставление двух подходов -- классического императивного и еще чего-то.
Обычно этим "чего-то" является ФП в мире языков, где почти полностью отсутсвует состоянии. А в мире сетевого взаимодействия ровно наоборот -- этот "чего-то"
как раз и является состоянием. Две крайности, а по середине императивщина.
Кодом людям нужно помогать!
Re[19]: REST: прохой\хороший интерфейс
От: Ватакуси Россия  
Дата: 07.02.20 11:19
Оценка:
В>>И если одназночность так и не пришла, валить сервер DDOS-ом?

S>exponential back-off какой-нибудь...

А смысл? 5xx почти всегда означает, что сервер не справился.
Все будет Украина!
Re[4]: REST: прохой\хороший интерфейс
От: Sharov Россия  
Дата: 07.02.20 11:35
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>Так и тут — опытный архитектор сходу видит в системе то состояние, которое он будет реплицировать.


А причем тут опыт, если понятно, что реплицировать надо всю бд, ибо это и есть состояние?

S>3. В любом из вариантов нет связи между состоянием лампы и этим запросом. То есть, скажем, прокси, который хранит у себя /lamps/2144, должен каждый раз бегать на origin сервер с conditional get, чтобы держать кэш когерентным.


А можно подробнее зачем в этой цепочке client ->http post -->server еще и прокси? Или он тут нужен для инвалидации кэша, тогда какая ему разница какой запрос (форма запроса), главное что post/resourceid?

S>Если у нас чуть более сложная операция, вроде "увеличить яркость на 10%", то всё становится ещё хуже — в рамках RPC мы вообще не можем отличить потерянный POST от последовательного увеличения яркости. Если для switch?state=on у нас есть очевидная стратегия обработки повторных запросов (хотя бы на сервере), то для вот таких вот операций ничего хорошего нету.


А request id тут не поможет?
Кодом людям нужно помогать!
Re[15]: REST: прохой\хороший интерфейс
От: Cyberax Марс  
Дата: 09.02.20 06:18
Оценка:
Здравствуйте, Sinclair, Вы писали:

C>>Сам по себе PUT никоим образом не спасёт от двойного создания объекта.

C>>Просто теряем сетевое соединение при ответе и клиент получает что-нибудь типа 509 Gateway Error и упс. Всё что он может — повторить запрос, который может создать объект заново.
S>Совершенно верно. Вот тут-то и спасает идемпотентность PUT. Что именно вам непонятно?
Станьте ёжиками! Что тут непонятного?

Вот пример: "PUT /user\r\n\r\n{name: "Vasiliy", last_name: "Pupkin"}". Что тут происходит при двойном запуске? Будут созданы два пользователя или один пользователь?

Если два пользователя (ID=1,2), то в списке пользователей будем видеть лишний объект. Если же один пользователь, то тогда будет проблема, если нужно таки создать ДВУХ пользователей (Vasiliy Ivanovich Pupkin и Vasility Petrovich Pupkin).

И никакие мантры вида "PUT же идемпотентен" это не решают. Нужно сразу и заранее проектировать это, и там уже будет без разницы через какой глагол посылать запросы. Хоть через GET.
Sapienti sat!
Re[5]: REST: прохой\хороший интерфейс
От: Sinclair Россия https://github.com/evilguest/
Дата: 10.02.20 06:58
Оценка:
Здравствуйте, samius, Вы писали:
S>Поставил "супер", но вот тут я принципиально не согласен. Не нужно противопоставлять RPC и REST вовсе. RPC — технология, позволяющая выполнить удаленный вызов и точка. REST — это архитектурный стиль организации работы распределенных приложений и сервисов. Это как сравнивать преимущества правил дорожного движения над автомобилем.
Под словом RPC понимают как минимум три вещи:
1. Методика, при которой у нас вызов, выглядяший в клиентском коде как обычный вызов процедуры, под капотом вызывает выполнение кода на удалённом сервисе
2. Конкретный стандарт RPC типа XML-RPC, Corba, COM
3. Стиль разработки API, в котором наружу выставляются "методы", у которых нет какой-либо семантики, кроме прикладной.

В конкретных примерах у нас зачастую все три соединяются в одном — например, у нас есть API без метаинформации о поведении методов, реализованный по стандарту XML-RPC, и к нему написана библиотека на клиентском языке, которая оборачивает вызовы эндпоинта в "процедуры".

Чисто теоретически, можно взять п.1, и приколхозить к нему инструменты для восстановления после сбоев.
Например, у всех get-методов можно добавить параметр "lastResponseTimestamp", а помимо прямого результата научить метод возвращать аналоги 304 Not Modified, а также передавать timestamp ответа. Потом можно прикрутить дельта-енкодинг.
Потом — компрессию. Потом прикрутить graceful degradation в зависимости от client capabilities, потому что у нас уже четыре версии протокола, и мы ни одну из них не можем заблокировать, т.к. под них всё ещё есть клиенты, которых мы не можем заставить проапгрейдиться.
У модифицирующих методов можно прикрутить ключи идемпотентности.

По факту, изо всего этого делают только ключи идемпотентности, да и то не всегда. Потому что технология диктует. Это как плыть против ветра — в REST это всё делается легко и естественно, и с гарантией обратной совместимости. В RPC — хренушки.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[18]: REST: прохой\хороший интерфейс
От: Sinclair Россия https://github.com/evilguest/
Дата: 10.02.20 07:02
Оценка:
Здравствуйте, Ватакуси, Вы писали:

В>И если одназночность так и не пришла, валить сервер DDOS-ом?

Откуда D DOS? Вы всё же в словаре-то смотрите незнакомые слова, прежде чем ими пользоваться
1. Со стороны сервера, вам в любом случае нужно думать о throttling. Потому что нет никакой гарантии, что клиенты ведут себя прилично, и не захотят вас просто завалить.
2. Со стороны клиента, достаточно брать паузу при ошибках. В реальной среде вы вряд ли получите DOS из-за проблем обратного канала: характерное время, за которое вы получаете таймаут — около 5 секунд (это оптимистично). Чаще делают таймауты в 30 секунд. "Долбя" сервер запросами раз в полминуты, вы никакого DOS не устроите.
3. Самое главное: а какая альтернатива? Никакого способа сделать лучше в природе не существует. См. "проблема двух генералов".
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[5]: REST: прохой\хороший интерфейс
От: Sinclair Россия https://github.com/evilguest/
Дата: 10.02.20 07:12
Оценка:
Здравствуйте, Sharov, Вы писали:

S>>Так и тут — опытный архитектор сходу видит в системе то состояние, которое он будет реплицировать.

S>А причем тут опыт, если понятно, что реплицировать надо всю бд, ибо это и есть состояние?
Ну конечно же нет. Вопрос в гранулярности этого состояния. Скажем, когда я бронирую себе конференцзал, мне нафиг не нужно состояние всех конференцзалов во всех офисах компании за бесконечный период.
Всё, что мне нужно — это интересующий меня диапазон в несколько дней.
REST позволяет мне описать эту предметную область таким образом, чтобы я, с одной стороны не был вынужден реплицировать "всю БД", а с другой стороны получал гарантию того, что интересующее меня состояние up to date.
И что у меня есть детерминированный способ это состояние изменить в желаемую для меня сторону.
В RPC у нас есть искушение сделать одним из двух способов:
1. Выбор на сервере. Я посылаю длительность слота, количество человек, диапазон поиска (см. тж. сервис приобретения билетов на сайте РЖД).
Проблема: если сервер забронировал билет, а я потерял ответ, у меня нет способа восстановиться без риска получить двойное бронирование. Да, чинится, но дополнительными рукопашными исправлениями в API.
2. Выбор на клиенте. Собственно, это будет рукопашный REST, т.к. у меня будет безопасный метод "получить расписание" и идемпотентный "забронировать слот".

S>А можно подробнее зачем в этой цепочке client ->http post -->server еще и прокси? Или он тут нужен для инвалидации кэша, тогда какая ему разница какой запрос (форма запроса), главное что post/resourceid?

Прокси, естественно, нужен для улучшения производительности. Смотрите: опять концепция REST даёт нам метаинформацию о том, что происходит. К примеру, можно всех пользователей офиса А запустить через прокси, и тогда как только один из них сходит на сервер за расписанием занятости ресурсов, остальные смогут получить ответ из локального прокси, а не через океан. Репликация состояния.
S>А request id тут не поможет?
Поможет, но о нём же надо подумать. С вероятностью 95% первая версия RPC API никаких RequestID содержать не будет — он же не требуется по спецификации.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[16]: REST: прохой\хороший интерфейс
От: Sinclair Россия https://github.com/evilguest/
Дата: 10.02.20 07:21
Оценка:
Здравствуйте, Cyberax, Вы писали:

C>Станьте ёжиками! Что тут непонятного?


C>Вот пример: "PUT /user\r\n\r\n{name: "Vasiliy", last_name: "Pupkin"}". Что тут происходит при двойном запуске? Будут созданы два пользователя или один пользователь?
Конечно же один. Читаем спецификацию HTTP, понимаем, что мы создаём ресурс по адресу /user.
Ровно его же мы получим обратно, выполнив GET /user
C>Если два пользователя (ID=1,2), то в списке пользователей будем видеть лишний объект. Если же один пользователь, то тогда будет проблема, если нужно таки создать ДВУХ пользователей (Vasiliy Ivanovich Pupkin и Vasility Petrovich Pupkin).
C>И никакие мантры вида "PUT же идемпотентен" это не решают. Нужно сразу и заранее проектировать это, и там уже будет без разницы через какой глагол посылать запросы. Хоть через GET.
Не нужно. Когда вы сядете проектировать REST API для управления пользователями, то вам сразу же станет понятно, что выглядеть запрос будет так:
PUT /users/c1b01406-c3da-44d8-b8d0-61d5c7d045b6/ \r\n\r\n{name: "Vasiliy", last_name: "Pupkin"}

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

Причём вы до этого дойдёте ещё до того, как начнёте делать задачу "создание пользователей". Потому что сначала вы сделаете
GET /users/

А потом
GET /users/c1b01406-c3da-44d8-b8d0-61d5c7d045b6/

И PUT у вас получится сам по себе.
Точнее, сначала вам захочется сделать
POST /users\r\n\r\n{name: "Vasiliy", last_name: "Pupkin"}

Но потом к вам придут недовольные пользователи с вопросом про задвоение пользователей, и вы поймёте, что удобство от использования PUT перевешивает сомнительную экономию от переноса вызова CreateUUID на сервер.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[17]: REST: прохой\хороший интерфейс
От: Cyberax Марс  
Дата: 10.02.20 07:57
Оценка:
Здравствуйте, Sinclair, Вы писали:

C>>Вот пример: "PUT /user\r\n\r\n{name: "Vasiliy", last_name: "Pupkin"}". Что тут происходит при двойном запуске? Будут созданы два пользователя или один пользователь?

S>Конечно же один. Читаем спецификацию HTTP, понимаем, что мы создаём ресурс по адресу /user.
S>Ровно его же мы получим обратно, выполнив GET /user
Я спецификацию HTTP знаю не то чтобы наизусть, но сильно лучше большинства людей, так как написал полностью соответствующую стандартам реализацию прокси для HTTP 1.1

В стандарте HTTP единственным способом сигнализации о создании нового объекта является код ответа HTTP. Этот код не является надёжным при сетевых сбоях. Так что повторный PUT по стандарту не является идемпотентным, так как НЕ МОЖЕТ вернуть 201 Created.

S>
S>PUT /users/c1b01406-c3da-44d8-b8d0-61d5c7d045b6/ \r\n\r\n{name: "Vasiliy", last_name: "Pupkin"}
S>

S>И отличать создание двух разных пользователей от повторных попыток создать одного и того же сервер будет легко.
Эта вот фигня "c1b01406-c3da-44d8-b8d0-61d5c7d045b6" и называется "ключ идемпотентности". В данном случае для этого используется внешний случайный ключ.

С тем же успехом можно сделать: "POST /users/operations\r\n\r\n{request_id: "2341234123412341234", op_name: "new", first_name: "Vasiliy", last_name: "Pupkin"}"

Более того, в данном случае так же возможна модель, когда что request_id вообще не сохраняется в постоянное хранилище и не является частью модели, а живёт на серверной стороне только в пределах некоторого retry-интервала.

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

Вы с какими-то странными мельницами воюете. Я ничего не говорил про экономию.
Sapienti sat!
Re[18]: REST: прохой\хороший интерфейс
От: Sinclair Россия https://github.com/evilguest/
Дата: 10.02.20 08:06
Оценка:
Здравствуйте, Cyberax, Вы писали:
C>Я спецификацию HTTP знаю не то чтобы наизусть, но сильно лучше большинства людей, так как написал полностью соответствующую стандартам реализацию прокси для HTTP 1.1
Я за вас очень рад
C>В стандарте HTTP единственным способом сигнализации о создании нового объекта является код ответа HTTP. Этот код не является надёжным при сетевых сбоях. Так что повторный PUT по стандарту не является идемпотентным, так как НЕ МОЖЕТ вернуть 201 Created.
Почему это он не может вернуть 201 Created?

S>>
S>>PUT /users/c1b01406-c3da-44d8-b8d0-61d5c7d045b6/ \r\n\r\n{name: "Vasiliy", last_name: "Pupkin"}
S>>

S>>И отличать создание двух разных пользователей от повторных попыток создать одного и того же сервер будет легко.
C>Эта вот фигня "c1b01406-c3da-44d8-b8d0-61d5c7d045b6" и называется "ключ идемпотентности". В данном случае для этого используется внешний случайный ключ.
Нет. Эта фигня называется "ID ресурса", а то, что она же используется в качестве ключа идемпотентности, это приятный бонус, полученный нами забесплатно.
C>С тем же успехом можно сделать: "POST /users/operations\r\n\r\n{request_id: "2341234123412341234", op_name: "new", first_name: "Vasiliy", last_name: "Pupkin"}"
С тем же, да не с тем. В случае с PUT идемпотентность операции дана нам стандартом; а в случае POST — навелосипедена. Т.е. я не могу написать никакого auto-retry механизма, который бы обрабатывал сбои самостоятельно и независимо от конкретного приложения.
C>Более того, в данном случае так же возможна модель, когда что request_id вообще не сохраняется в постоянное хранилище и не является частью модели, а живёт на серверной стороне только в пределах некоторого retry-интервала.
Вот именно. В PUT такая рисковая реализация невозможна. А вы предлагаете на ровном месте разложить грабли — клиент, который не смог записать результат POST к себе в базу (например, из-за переполнения диска) после починки прекрасно стартует с места "таак, вот мой request id, попробую-ка я ещё раз", и задвоит объект.
C>Вы с какими-то странными мельницами воюете. Я ничего не говорил про экономию.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re: REST: прохой\хороший интерфейс
От: Teolog  
Дата: 10.02.20 08:21
Оценка:
Хороший интерфейс — а что, тут был интерфейс, вроде все просто работало.
Плохой интрефйейс — что не нравится этой сволочи, где код ошибки, и почему запрос нужно повторять 99 раз. Где чертова документация вообще. И домашний адрес автора, да.
Re[6]: REST: прохой\хороший интерфейс
От: Sharov Россия  
Дата: 10.02.20 14:24
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>Здравствуйте, Sharov, Вы писали:


S>>>Так и тут — опытный архитектор сходу видит в системе то состояние, которое он будет реплицировать.

S>>А причем тут опыт, если понятно, что реплицировать надо всю бд, ибо это и есть состояние?
S>Ну конечно же нет. Вопрос в гранулярности этого состояния. Скажем, когда я бронирую себе конференцзал, мне нафиг не нужно состояние всех конференцзалов во всех офисах компании за бесконечный период.
S>Всё, что мне нужно — это интересующий меня диапазон в несколько дней.

Ну как же нет, когда таких пользователей может быть много, и мало ли какие записи ими будут востребованы? Репликация на уровне данных, master-slave, самый простой вариант.
Работает из коробки.


S>>А можно подробнее зачем в этой цепочке client ->http post -->server еще и прокси? Или он тут нужен для инвалидации кэша, тогда какая ему разница какой запрос (форма запроса), главное что post/resourceid?

S>Прокси, естественно, нужен для улучшения производительности. Смотрите: опять концепция REST даёт нам метаинформацию о том, что происходит. К примеру, можно всех пользователей офиса А запустить через прокси, и тогда как только один из них сходит на сервер за расписанием занятости ресурсов, остальные смогут получить ответ из локального прокси, а не через океан. Репликация состояния.

Это понятно, на пути POST запроса на кой там прокси, если только не для инвалидации?
Кодом людям нужно помогать!
Re[7]: REST: прохой\хороший интерфейс
От: Sinclair Россия https://github.com/evilguest/
Дата: 10.02.20 16:34
Оценка:
Здравствуйте, Sharov, Вы писали:

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

Да вы смеётесь. Вот у вас, скажем, жалкие 40000 пользователей. Репликация всех изменений ко всем просто положит вам все каналы.

S>Репликация на уровне данных, master-slave, самый простой вариант.

S>Работает из коробки.
Эта репликация позволяет получать данные а) на чтение и б) с опозданием. Даже если она заработает для нужного нам масштаба, она никак не решает вопрос "а как мне внести изменения так, чтобы иметь детерминированный способ восстановления после сбоя".

S>Это понятно, на пути POST запроса на кой там прокси, если только не для инвалидации?

Для инвалидации конечно. По стандарту, прокси видя PUT реквест, должен считать кэш ресурса по его адресу устаревшим. Без дополнительного раундтрипа на апстрим.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[19]: REST: прохой\хороший интерфейс
От: Cyberax Марс  
Дата: 10.02.20 23:01
Оценка:
Здравствуйте, Sinclair, Вы писали:

C>>В стандарте HTTP единственным способом сигнализации о создании нового объекта является код ответа HTTP. Этот код не является надёжным при сетевых сбоях. Так что повторный PUT по стандарту не является идемпотентным, так как НЕ МОЖЕТ вернуть 201 Created.

S>Почему это он не может вернуть 201 Created?
Сценарий:
1. Создаём объект (с помощью PUT).
2. Сервер создаёт объект и возвращает 201.
3. Соединение рвётся, клиент ответ не получает.
4. Клиент пробует снова. Сервер ОБЯЗАН вернуть обычный 200 OK.

Т.е. PUT не идемпотентен по дизайну.

C>>Эта вот фигня "c1b01406-c3da-44d8-b8d0-61d5c7d045b6" и называется "ключ идемпотентности". В данном случае для этого используется внешний случайный ключ.

S>Нет. Эта фигня называется "ID ресурса", а то, что она же используется в качестве ключа идемпотентности, это приятный бонус, полученный нами забесплатно.
Это внешний ключ. Называть его можно как угодно, но суть не меняется.

Кроме того, он может быть неприменим по ряду причин:
1. Пользователям может хотеться приятный идентификатор, а не UUID.
2. Пользователям может требоваться гарантия невозможности утечки данных через специально сгенерированные клиентом UUID'ы.

C>>С тем же успехом можно сделать: "POST /users/operations\r\n\r\n{request_id: "2341234123412341234", op_name: "new", first_name: "Vasiliy", last_name: "Pupkin"}"

S>С тем же, да не с тем. В случае с PUT идемпотентность операции дана нам стандартом; а в случае POST — навелосипедена. Т.е. я не могу написать никакого auto-retry механизма, который бы обрабатывал сбои самостоятельно и независимо от конкретного приложения.
Стандарт ничего не обеспечивает, там только указаны требования к реализации ("станьте ёжиками").

C>>Более того, в данном случае так же возможна модель, когда что request_id вообще не сохраняется в постоянное хранилище и не является частью модели, а живёт на серверной стороне только в пределах некоторого retry-интервала.

S>Вот именно. В PUT такая рисковая реализация невозможна. А вы предлагаете на ровном месте разложить грабли — клиент, который не смог записать результат POST к себе в базу (например, из-за переполнения диска) после починки прекрасно стартует с места "таак, вот мой request id, попробую-ка я ещё раз", и задвоит объект.
Зато оно позволит избавиться от другого класса ошибок:
1. Клиент для оператора A делает PUT и создаёт объект. Но GPRS-модем — лопух, и аппаратура тоже. Так что ответ не приходит.
2. Оператор Б в офисе видит: "О! Пришёл новый пользователь! Сейчас я к нему детали из Linked-In добавлю!", — и таки добавляет детали.
3. Клиент для оператора А отвечает: "А вот хрен ты у меня чего-то добавишь!" И делает повторный PUT с начальными деталями, затирая изменения.

ЧСХ, в чистом HTTP проблема решения не имеет. If-Modified-Since и товарищи применимы по стандарту только к GET, и даже при его игнорировании всё равно недостаточны.

Понятно, что на практике её можно решить, вводя версирование или блокировки на уровне прикладного протокола.
Sapienti sat!
Re[20]: REST: прохой\хороший интерфейс
От: Sinclair Россия https://github.com/evilguest/
Дата: 11.02.20 03:15
Оценка:
Здравствуйте, Cyberax, Вы писали:

C>Сценарий:

C>1. Создаём объект (с помощью PUT).
C>2. Сервер создаёт объект и возвращает 201.
C>3. Соединение рвётся, клиент ответ не получает.
C>4. Клиент пробует снова. Сервер ОБЯЗАН вернуть обычный 200 OK.
Нет. Если сервер детектит сохранение того же объекта, он имеет право вернуть 201. Вы недостаточно внимательно читали спецификацию. Как раз идемпотентность от PUT там потребована в самом начале
C>Это внешний ключ. Называть его можно как угодно, но суть не меняется.
Совершенно верно. В REST у всех ресурсов есть уникальные URL.

C>1. Пользователям может хотеться приятный идентификатор, а не UUID.

Не проблема — можно использовать приятный идентификатор. Правда, с ним выше риск получить 409 на ровном месте.
C>2. Пользователям может требоваться гарантия невозможности утечки данных через специально сгенерированные клиентом UUID'ы.
Не проблема — клиенты могут использовать любую технологию порождения ID. Не хотят утечки данных — пусть не используют их при генерации UUID.
З.Ы. Вы в курсе, что MAC адрес в гражданских реализациях генераторов GUID не используется уже больше десяти лет?

C>Стандарт ничего не обеспечивает, там только указаны требования к реализации ("станьте ёжиками").

Погодите. Вы что, не понимаете, как именно реализовать идемпотентность? Тогда всё ещё хуже, чем я думал. Ешё раз поясню: RPC не содержит даже требования идемпотентности. Это означает, что архитекторы (большинство из которых квалифицированы менее, чем вы) просто забьют на них.
Вот вы берёте REST, и несмотря на подробное изложение требований к API ухитряетесь делать вид, что идемпотентность — это какая-то rocket science.
S>>Вот именно. В PUT такая рисковая реализация невозможна. А вы предлагаете на ровном месте разложить грабли — клиент, который не смог записать результат POST к себе в базу (например, из-за переполнения диска) после починки прекрасно стартует с места "таак, вот мой request id, попробую-ка я ещё раз", и задвоит объект.
C>Зато оно позволит избавиться от другого класса ошибок:
C>1. Клиент для оператора A делает PUT и создаёт объект. Но GPRS-модем — лопух, и аппаратура тоже. Так что ответ не приходит.
C>2. Оператор Б в офисе видит: "О! Пришёл новый пользователь! Сейчас я к нему детали из Linked-In добавлю!", — и таки добавляет детали.
C>3. Клиент для оператора А отвечает: "А вот хрен ты у меня чего-то добавишь!" И делает повторный PUT с начальными деталями, затирая изменения.
Отлично. И как этот же сценарий выглядит в подходе с POST и кратковременным requestID? У нас есть два варианта:
— requestID протух. Клиент А, очевидно, создаст дубля.
— requestID ещё жив. Что получит клиент А?
C>ЧСХ, в чистом HTTP проблема решения не имеет. If-Modified-Since и товарищи применимы по стандарту только к GET, и даже при его игнорировании всё равно недостаточны.
Имеет. Для начала, нужно понять, что проблема lost update в принципе не связана с созданием. У нас два глухих клиента могут постить чередующиеся конфликтующие апдейты, независимо от выбора глаголов и вообще подхода к проектированию API.
А как только вы решите эту проблему, то и обработка создания объектов проблемы у вас не вызовет.
Далее, можно всё же прочитать спецификацию, и найти, что для нашего случая, помимо версии на уровне прикладного протокола, есть штатный механизм.
Если клиент хочет быть уверен, что он именно создаёт новый ресурс, а не затирает чужой, то

If-None-Match can also be used with a value of "*" to prevent an
unsafe request method (e.g., PUT) from inadvertently modifying an
existing representation of the target resource when the client
believes that the resource does not have a current representation
(Section 4.2.1 of [RFC7231]). This is a variation on the "lost
update" problem that might arise if more than one client attempts to
create an initial representation for the target resource.

Аналогично можно решить проблему конкурирующих PUT, которая возникает даже при идеальном качестве связи. Только применять надо If-Match.
C>Понятно, что на практике её можно решить, вводя версирование или блокировки на уровне прикладного протокола.
Можно. С версионированием работать может оказаться удобнее, чем в голых хидерах. В частности, оно позволяет лёгким манием руки прикрутить хранение всей истории модификаций. Но это не отменяет того факта, что голый HTTP 1.1 предусматривает решение множества проблем, которые вам кажутся неразрешимыми.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[6]: REST: прохой\хороший интерфейс
От: samius Япония http://sams-tricks.blogspot.com
Дата: 11.02.20 04:38
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>Здравствуйте, samius, Вы писали:

S>>Поставил "супер", но вот тут я принципиально не согласен. Не нужно противопоставлять RPC и REST вовсе. RPC — технология, позволяющая выполнить удаленный вызов и точка. REST — это архитектурный стиль организации работы распределенных приложений и сервисов. Это как сравнивать преимущества правил дорожного движения над автомобилем.
S>Под словом RPC понимают как минимум три вещи:
S>1. Методика, при которой у нас вызов, выглядяший в клиентском коде как обычный вызов процедуры, под капотом вызывает выполнение кода на удалённом сервисе
Я об этом.
S>2. Конкретный стандарт RPC типа XML-RPC, Corba, COM
Допускаю, но в этом случае нужен определенный контекст, например, введенный упоминанием конкретного стандарта.
S>3. Стиль разработки API, в котором наружу выставляются "методы", у которых нет какой-либо семантики, кроме прикладной.
Это субъективно. Этот же самый стиль вполне может быть назван REST. Есть тому масса примеров, и даже литература о REST вовсе без упоминания о сбоях и идемпотентности.

S>В конкретных примерах у нас зачастую все три соединяются в одном — например, у нас есть API без метаинформации о поведении методов, реализованный по стандарту XML-RPC, и к нему написана библиотека на клиентском языке, которая оборачивает вызовы эндпоинта в "процедуры".


Этого достаточно, что бы выдавать свой API за REST.

S>Чисто теоретически, можно взять п.1, и приколхозить к нему инструменты для восстановления после сбоев.

S>Например, у всех get-методов можно добавить параметр "lastResponseTimestamp", а помимо прямого результата научить метод возвращать аналоги 304 Not Modified, а также передавать timestamp ответа. Потом можно прикрутить дельта-енкодинг.
S>Потом — компрессию. Потом прикрутить graceful degradation в зависимости от client capabilities, потому что у нас уже четыре версии протокола, и мы ни одну из них не можем заблокировать, т.к. под них всё ещё есть клиенты, которых мы не можем заставить проапгрейдиться.
S>У модифицирующих методов можно прикрутить ключи идемпотентности.

S>По факту, изо всего этого делают только ключи идемпотентности, да и то не всегда. Потому что технология диктует. Это как плыть против ветра — в REST это всё делается легко и естественно, и с гарантией обратной совместимости. В RPC — хренушки.


Об этом вообще мало кто заморачивается. Вот, наткнулся не так давно...
https://labs.ig.com/rest-trading-api-reference/service-detail?id=542
Вытащили наружу обернутые POST-ом методы, даже забыв идентификатор ресурса в теле запроса. И представили под вывеской REST.

У меня вообще создается впечатление, что попытки отличать "REST" от "RPC" по наличию механизмов восстановления присущи лишь местному клубу.
Re[7]: REST: прохой\хороший интерфейс
От: Sinclair Россия https://github.com/evilguest/
Дата: 11.02.20 05:18
Оценка:
Здравствуйте, samius, Вы писали:

S>У меня вообще создается впечатление, что попытки отличать "REST" от "RPC" по наличию механизмов восстановления присущи лишь местному клубу.

Нет. Исходно аббревиатура ReST означает "Representational State Transfer", и введена в диссертации Филдинга от 2000 года. Дело даже не в наличии механизмов восстановления, а в самой философии API.
RESTful API сразу проектируется так, что у нас есть некоторое "состояние" разделяемых данных, и мы можем это состояние получить через вызовы GET/HEAD и влиять на него при помощи PUT/PATCH/DELETE/POST.
То, что при этом у нас появляются обобщённые подходы к обработке сбоев — это побочный эффект такого выбора. Наряду с кэшированием, компрессией, частичной передачей и т.п.
По большому счёту, REST можно изобрести и независимо от HTTP. Я подозреваю, что механизм синхронизации баз в Lotus Notes/Domino, реализует что-то типа того же REST.
Или, например, можно запилить REST поверх SQL, выставив набор view с instead-of триггерами. Т.е. все операции с базой будут идти не через хранимки, а через DML (select/insert/update/delete).

Там приятным побочным эффектом будет, к примеру, возможность "отгрузить" сразу пачку ордеров без cross apply и прочей магии:
update orders set status = 'shipped' from orders inner join delivery_lines dl on orders.id = dl.order_id where dl.id = @deliveryId


К сожалению, с публикаций первоисточников прошло много времени. В интернет набежала толпа недоумков, которые слышали про REST только в пересказе других недоумков. Они думают, что REST — это любой JSON over HTTP.
Не надо их читать. Надо читать классику типа http://shop.oreilly.com/product/9780596529260.do.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[8]: REST: прохой\хороший интерфейс
От: samius Япония http://sams-tricks.blogspot.com
Дата: 11.02.20 06:49
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>Здравствуйте, samius, Вы писали:


S>>У меня вообще создается впечатление, что попытки отличать "REST" от "RPC" по наличию механизмов восстановления присущи лишь местному клубу.

S>Нет. Исходно аббревиатура ReST означает "Representational State Transfer", и введена в диссертации Филдинга от 2000 года. Дело даже не в наличии механизмов восстановления, а в самой философии API.
S>RESTful API сразу проектируется так, что у нас есть некоторое "состояние" разделяемых данных, и мы можем это состояние получить через вызовы GET/HEAD и влиять на него при помощи PUT/PATCH/DELETE/POST.
S>То, что при этом у нас появляются обобщённые подходы к обработке сбоев — это побочный эффект такого выбора. Наряду с кэшированием, компрессией, частичной передачей и т.п.
S>По большому счёту, REST можно изобрести и независимо от HTTP. Я подозреваю, что механизм синхронизации баз в Lotus Notes/Domino, реализует что-то типа того же REST.

Сам Филдинг упоминает о том, что РЕСТ основан на совокупности стилей, перечисленных в главе 3 его диссертации. Один из — Client-Stateless-Server (CSS), описанный в 1994-м (https://www.ics.uci.edu/~fielding/pubs/dissertation/net_arch_styles.htm). РЕСТ — всего лишь гибрид. В любом случае, Филдинг не преподносит его как изобретение. Объединение, наследование — да. И по сути этого объединения вышло так, что работа с состоянием не выглядит в этом объединении ключевой. Безусловно является, но не выглядит таковой. Замылилась репрезентативностью.

S>Или, например, можно запилить REST поверх SQL, выставив набор view с instead-of триггерами. Т.е. все операции с базой будут идти не через хранимки, а через DML (select/insert/update/delete).

Запилить можно.

S>Там приятным побочным эффектом будет, к примеру, возможность "отгрузить" сразу пачку ордеров без cross apply и прочей магии:

S>
S>update orders set status = 'shipped' from orders inner join delivery_lines dl on orders.id = dl.order_id where dl.id = @deliveryId
S>


S>К сожалению, с публикаций первоисточников прошло много времени. В интернет набежала толпа недоумков, которые слышали про REST только в пересказе других недоумков. Они думают, что REST — это любой JSON over HTTP.

S>Не надо их читать. Надо читать классику типа http://shop.oreilly.com/product/9780596529260.do.

Читать — это хорошо. Свой API можно сделать правильно и избежать некоторое кол-во проблем. Проблема-то несколько в другом. Есть некоторое кол-во сервисов, предоставляющих REST API в духе JSON over HTTP (не вдаваясь в математику HTTP). Как клиенту мне сложно с ними дискутировать о том, каких недоумков им не нужно читать, проектируя REST API. Дешевле закостылить клиента, чем сподвигнуть сервис на переписывание API по фен-шую.
Хочется сказать им: ребята, надо делать вот так ... Но у Филдинга слово "идемпотентность" в работе не упоминается, а на каждую книжку, где оно упоминается вместе с REST, найдется пяток таких книг, где его нет.
Re[6]: REST: прохой\хороший интерфейс
От: Pavel Dvorkin Россия  
Дата: 11.02.20 11:26
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>Чисто теоретически, можно взять п.1, и приколхозить к нему инструменты для восстановления после сбоев.

S>Например, у всех get-методов можно добавить параметр "lastResponseTimestamp", а помимо прямого результата научить метод возвращать аналоги 304 Not Modified, а также передавать timestamp ответа.

Можно и проще, как это сделано, например , в thrift. Сервер при ошибке выбрасывает исключение, которое портируется на клиент и представляется там на языке программирования клиента. Так что разницы между RPC и LPC практически нет в этом плане.
With best regards
Pavel Dvorkin
Re[10]: REST: прохой\хороший интерфейс
От: Sharov Россия  
Дата: 11.02.20 12:14
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>Эмм, не знаю насчёт "замылилась". У Филдинга representational означает, что мы не лезем в состояние сервера напрямую. Всё, что у нас есть — некоторое представление этого состояния; и вся коммуникация между клиентом и сервером выражена в терминах этого представления.


А что значит состояние сервера, значение регистров цпу + озу, бд? Почему используется слово "представление", а не слово "часть" данных.


S>И, с точки зрения Филдинга, REST — первичен, как абстрактная модель. HTTP 1.1 — это, с его точки зрения, всего лишь пример применения концепции REST к World Wide Web. (Глава 6.3).


Фундаментальнее скорее, ибо полиморфизм (get,post..) во весь рост, но вдохновлялся http.
Кодом людям нужно помогать!
Re[7]: REST: прохой\хороший интерфейс
От: Sinclair Россия https://github.com/evilguest/
Дата: 12.02.20 04:02
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:
S>>Например, у всех get-методов можно добавить параметр "lastResponseTimestamp", а помимо прямого результата научить метод возвращать аналоги 304 Not Modified, а также передавать timestamp ответа.
PD>Можно и проще, как это сделано, например , в thrift. Сервер при ошибке выбрасывает исключение, которое портируется на клиент и представляется там на языке программирования клиента. Так что разницы между RPC и LPC практически нет в этом плане.
Что делать при ошибке — понятно. Можно даже заставить все исключения наследоваться от RetryableException либо от FatalException.
Непонятно, как реализовать responseTimeStamp и 304 Not Modified. Это не ошибка, а сигнал о том, что данные не изменились.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[8]: REST: прохой\хороший интерфейс
От: Pavel Dvorkin Россия  
Дата: 12.02.20 11:44
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>Что делать при ошибке — понятно. Можно даже заставить все исключения наследоваться от RetryableException либо от FatalException.

S>Непонятно, как реализовать responseTimeStamp и 304 Not Modified. Это не ошибка, а сигнал о том, что данные не изменились.

Мне кажется, что ты пытаешься навязать RPC психологию HTTP, отсюда все проблемы , в частности, желание получить 304

304 Not Modified — сервер возвращает такой код, если клиент запросил документ методом GET, использовал заголовок If-Modified-Since или If-None-Match и документ не изменился с указанного момента.

Да, для HTTP это имеет смысл. Но вот тебе иной пример

Я не буду, конечно, утверждать, что клиент РБД связывается с ней по именно по RPC. Там внизу скорее всего иначе. Но суть от этого не меняется.

Запросил ты что-то с помощью SELECT и что ? Кто там не изменился и что должно возвращаться ? Нет такого понятия — не изменился. Просил — получи, а потом сам и разбирайся, что там изменилось, а что нет. Да еще учти, что пока разбираешься, там что-то могло измениться. Хочешь знать, когда изменялось — предусмотри в таблице timestamp.

А 304... Ну что 304 ? Придуман во времена, когда ресурсы были в основном статическими, а If-Modified-Since реализовать было предельно просто : взять время последней модификации файла, и все дела.

А потом начали HTTP, который вовсе не был предназначен изначально для интерфейса со сложным серверным кодом, применять именно для этой цели. Понятно, что без проблем не обошлось.
With best regards
Pavel Dvorkin
Re[9]: REST: прохой\хороший интерфейс
От: Sinclair Россия https://github.com/evilguest/
Дата: 12.02.20 14:02
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

PD>Мне кажется, что ты пытаешься навязать RPC психологию HTTP, отсюда все проблемы , в частности, желание получить 304

Вот ровно всё — мимо.
1. Во-первых, проблемы не у меня, а у RPC. Это ущербная концепция, плохо применимая в сетевых реалиях.
2. Во-вторых, никакой "психологии" тут нет. Есть банальный прагматизм, выработанный многолетней практикой.

PD>304 Not Modified — сервер возвращает такой код, если клиент запросил документ методом GET, использовал заголовок If-Modified-Since или If-None-Match и документ не изменился с указанного момента.

Я в курсе, что такое Not Modified.
PD>Да, для HTTP это имеет смысл.
Конкретный код — да, имеет смысл только в рамках HTTP.
А сама концепция кэширования и delta-encoding выходит далеко за рамки HTTP.
PD>Я не буду, конечно, утверждать, что клиент РБД связывается с ней по именно по RPC. Там внизу скорее всего иначе. Но суть от этого не меняется.
PD>Запросил ты что-то с помощью SELECT и что ? Кто там не изменился и что должно возвращаться ? Нет такого понятия — не изменился. Просил — получи, а потом сам и разбирайся, что там изменилось, а что нет.
Ну, так это-то и плохо. Качаем терабайт данных для того, чтобы заменить одну строчку. Павел, ты уверен, что это — лучше, чем HTTP?
PD>Да еще учти, что пока разбираешься, там что-то могло измениться. Хочешь знать, когда изменялось — предусмотри в таблице timestamp.
Если тебе интересно, как сделать change tracking в RDBMS — обращайся. Я участвую в топиках на эту тему в соответствующем форуме в среднем ежегодно

PD>А 304... Ну что 304 ? Придуман во времена, когда ресурсы были в основном статическими, а If-Modified-Since реализовать было предельно просто : взять время последней модификации файла, и все дела.

(facepalm).
PD>А потом начали HTTP, который вовсе не был предназначен изначально для интерфейса со сложным серверным кодом, применять именно для этой цели. Понятно, что без проблем не обошлось.
И опять ровно всё — мимо.
Сначала для интерфейса со "сложным серверным кодом" начали применять RPC. Потом — RMI. Применение HTTP для этого возникло существенно позже. И, естественно, сначала усилия были вложены в противоположную сторону — люди взяли из HTTP ровно один глагол (самый бесполезный) и завернули RPC/RMI в XML over HTTP.
Получился проклятый SOAP.
И только через семь-восемь лет после публикации диссертации Филдинга передовики начали понимать, как правильно делать современные API в интернете. Чтобы они работали быстро, надёжно, и масштабируемо.
RPC тут оказался мимо тазика — во всех его инкарнациях.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[11]: REST: прохой\хороший интерфейс
От: Sharov Россия  
Дата: 12.02.20 16:46
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

PD>RPC, с твоего разрешения, лежит под DCOM/OLE (ты это должен знать), а там гораздо более сложная логика, чем в бизнес-приложениях. Убери RPC — и Windows больше нет.


А разве WCF беэ DCOM/OLE не обходится? А rpc там в полный рост.
Кодом людям нужно помогать!
Re[12]: REST: прохой\хороший интерфейс
От: Sinclair Россия https://github.com/evilguest/
Дата: 12.02.20 17:28
Оценка:
Здравствуйте, Sharov, Вы писали:

S>А разве WCF беэ DCOM/OLE не обходится? А rpc там в полный рост.

Тут опять путаница терминологии. RPC, который в WCF — это общий термин, стиль работы API. А RPC в DCOM — это конкретная технология маршаллинга.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[13]: REST: прохой\хороший интерфейс
От: · Великобритания  
Дата: 12.02.20 22:27
Оценка:
Здравствуйте, Sharov, Вы писали:

S>>На всякий случай поясню, что такие вопросы обсуждать бессмысленно. Конструктивную беседу можно вести только в рамках более-менее очерченной задачи.

S>>Придумай задачу, для которой тебе кажется естественным некий RPC-API (можешь сразу и набросать его черновик), а REST-API вызывает затруднения. Я покажу, как сделать REST для этой задачи, и можно будет сравнить достоинства и недостатки.
S>Влезу. Ну, например, калькулятор, который на удаленной машине чего-то считает. rpc прямолинеен, а вот с rest придется попотеть. Вообще, как я понимаю, rest нужен, когда мы имеем дело
S>с необходимостью CRUD чего-то. Если нам просто нужны чьи-то выч. ресурсы и время, без соотв. crud, то rpc вполне подойдет.
Калькулятор это stateless — скучно и тривиально, решается одинаково просто практически на чём угодно левой пяткой во сне. А REST это всё-таки Representational state transfer.

Хотя даже в таком случае — когда ты начнёшь задавать вопрос как передавать состояние "сервер сломался", "клиент корявое выражение послал", "серверу от напора клиентов поплохело, надо бы им как-то объяснить, чтобы не ломились так часто", "а в каком виде будем договариваться в каком виде передавать выражение — xml/json/whatever?", "а как договориться о формате компрессии?", "а как обеспечить секьюрную передачу инфы?". Все эти вопросы тебе придётся колхозить практически в любой существующей RPC-технологии, когда как в REST это всё из коробки и прикручивается тривиально.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Отредактировано 12.02.2020 22:32 · . Предыдущая версия . Еще …
Отредактировано 12.02.2020 22:27 · . Предыдущая версия .
Re[14]: REST: прохой\хороший интерфейс
От: Sharov Россия  
Дата: 12.02.20 22:41
Оценка:
Здравствуйте, ·, Вы писали:

S>>Влезу. Ну, например, калькулятор, который на удаленной машине чего-то считает. rpc прямолинеен, а вот с rest придется попотеть. Вообще, как я понимаю, rest нужен, когда мы имеем дело

S>>с необходимостью CRUD чего-то. Если нам просто нужны чьи-то выч. ресурсы и время, без соотв. crud, то rpc вполне подойдет.
·>Калькулятор это stateless — скучно и тривиально, решается одинаково просто практически на чём угодно левой пяткой во сне. А REST это всё-таки Representational state transfer.

Нам не нужен state, я же написал об этом. Нам нужны выч. ресурсы -- закинул задачу и пошел себе дальше.
Кодом людям нужно помогать!
Re[15]: REST: прохой\хороший интерфейс
От: · Великобритания  
Дата: 12.02.20 22:57
Оценка:
Здравствуйте, Sharov, Вы писали:

S>·>Калькулятор это stateless — скучно и тривиально, решается одинаково просто практически на чём угодно левой пяткой во сне. А REST это всё-таки Representational state transfer.

S>Нам не нужен state, я же написал об этом. Нам нужны выч. ресурсы -- закинул задачу и пошел себе дальше.
Т.е. код примерно такой:
try
{
    result = remote.calculator(expression);
}
catch(RemoteException e) {
    //do what??
}

Вот уже надо как-то отличать типы RemoteException чтобы либо показать пользователю "у вас тут что-то не так" или "сервер занят. Повторить?".

Да, я ещё там в своё сообщение параграф вставил, ты видимо не заметил.

Хотя даже в таком случае — когда ты начнёшь задавать вопрос как передавать состояние "сервер сломался", "клиент корявое выражение послал", "серверу от напора клиентов поплохело, надо бы им как-то объяснить, чтобы не ломились так часто", "а в каком виде будем договариваться в каком виде передавать выражение — xml/json/whatever?", "а как договориться о формате компрессии?", "а как обеспечить секьюрную передачу инфы?". Все эти вопросы тебе придётся колхозить практически в любой существующей RPC-технологии, когда как в REST это всё из коробки и прикручивается тривиально.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[13]: REST: прохой\хороший интерфейс
От: Sinclair Россия https://github.com/evilguest/
Дата: 13.02.20 03:22
Оценка:
Здравствуйте, Sharov, Вы писали:

S>Влезу. Ну, например, калькулятор, который на удаленной машине чего-то считает. rpc прямолинеен, а вот с rest придется попотеть.

Даже напрячься не успеем.
GET /calculate?expression=((1800*999)-677)/65866556

Более интересный пример:
GET /factor?number=568132681318943132168430


Пример калькулятора, который на удаленной машине чего-то считает, в котором REST выигрывает у RPC:
GET /pi
Range: bytes 0-1000

Этот запрос может быть отдан из кэша любым промышленным прокси-сервером.

Вообще, как я понимаю, rest нужен, когда мы имеем дело
S>с необходимостью CRUD чего-то. Если нам просто нужны чьи-то выч. ресурсы и время, без соотв. crud, то rpc вполне подойдет.
REST нужен тогда, когда мы работаем с разделяемым состоянием.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[15]: REST: прохой\хороший интерфейс
От: Sinclair Россия https://github.com/evilguest/
Дата: 13.02.20 03:33
Оценка:
Здравствуйте, Sharov, Вы писали:
S>Нам не нужен state, я же написал об этом. Нам нужны выч. ресурсы -- закинул задачу и пошел себе дальше.
Вот прямо отличный пример. "Пошёл себе дальше" подразумевает, наверное, возможность как-то потом забрать результат, так?
Значит, у нас появляется сущность "задача", и её состояние: "в очереди", "в процессе выполнения", "выполнена", "сбой выполнения". Это состояние нужно синхронизовывать между клиентом и сервером.
Всё, REST начинает выигрывать у RPC ещё до начала забега — как раз потому, что он позволяет внятно описать CRUD над множеством задач. Ваши первые две-три реализации RPC будут страдать от детских болезней вроде "нечаянно поставил одну и ту же задачу в очередь дважды" или "задачу поставил — результат потерял".
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[12]: REST: прохой\хороший интерфейс
От: Pavel Dvorkin Россия  
Дата: 13.02.20 03:45
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>Ну вот. При этом инкрементальность приходилось велосипедить самому. И вряд ли удалось сначала сделать протокол без инкрементальности, а потом добавить к нему инкрементальность обратно-совместимым способом.


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

S>Павел, очень, очень советую почитать литературу. Ссылка на бесплатную книжку приведена прямо в этом топике. "Свобода" RPC означает, по большому счёту, свободу писать некорректные и неоптимизируемые протоколы.


Спасибо за совет

PD>>HTTP — какой глагол употребим ?

S>С точки зрения HTTP, совершенно неважно, что там происходит "на сервере". Важно то, как мы это представляем клиенту. Representational State Transfer. Если клиенту выставляется такая модель ресурсов, что при применении этого действия к модели добавляется новый ресурс, то делаем через PUT.
S>На всякий случай поясню, что такие вопросы обсуждать бессмысленно. Конструктивную беседу можно вести только в рамках более-менее очерченной задачи.
S>Придумай задачу, для которой тебе кажется естественным некий RPC-API (можешь сразу и набросать его черновик), а REST-API вызывает затруднения. Я покажу, как сделать REST для этой задачи, и можно будет сравнить достоинства и недостатки.

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

На сервер города N добавляется новая Персона. Все, что о ней известно на момент ее поступления на сервер — инкогнито, недурной наружности, в партикулярном платье, ходит этак по комнате, и в лице этакое рассуждение... физиономия... поступки, и здесь (вертит рукою около лба) много, много всего.
С использованием методов машинного интеллекта при участии персон Городничего, Ляпкина-Тяпкина, Добчинского и Бобчинского производится классификация этой Персоны — относится ли она к категории Ревизоры
Если эта классификация отнесет его к категории Ревизор, то необходимо
1. Надеть колпаки на больных в богоугодном заведении и проследить, чтобы они были чистыми
2. Сделать, чтобы больные не походили бы на кузнецов
3. Над каждой кроватью написать по-латыни название болезни
4. Удалить всех гусей с гусенками из присутственных мест, а также удалить охотничий арапник там же
5. Провести воспитательную беседу с учителями (алгоритм TBD) и особо им указать, чтобы стулья не ломали
6. Сказать Держиморде, чтобы не слишком давал воли кулакам своим
7. Подготовить некую сумму денег для взятки.

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

Если же он не Ревизор, то все, что надо — записать его в книгу проезжающих и предоставить собственной судьбе.

Так что же это — POST, PUT или DELETE ? И чего именно ?

Для RPC —

class Person {
String наружность;
String платье;
//...
}

void addPerson(Person person);

а там уж что будет, то и будет.


PD>>RPC, с твоего разрешения, лежит под DCOM/OLE (ты это должен знать), а там гораздо более сложная логика, чем в бизнес-приложениях. Убери RPC — и Windows больше нет.

S>Я вас умоляю. DCOM/OLE работает в тепличных условиях локальной машины. В нём ситуация "не удалось доставить результат вызова обратно" — редкость. И когда она случается, результат лечат перезагрузкой машины.

COM работает в условиях локальной машины, а DCOM — это Distributed COM, работает в локальной сети.

S>Использовать DCOM через океан — упаси байт! Представь себе приложение резервирования авиабилетов, написанное на DCOM. Или хотя бы онлайн-регистрации. Нафиг-нафиг.


Причин же, почему DCOM для этого не используется , три

1. HTTP был сделан раньше, вот его и продолжвли использовать
2. COM нет в линуксе, что сразу ставит крест на возможности его использования для этой цели
3. COM не подерживают все браузеры даже в Windows.
With best regards
Pavel Dvorkin
Отредактировано 13.02.2020 4:22 Pavel Dvorkin . Предыдущая версия .
Re[13]: REST: прохой\хороший интерфейс
От: Sinclair Россия https://github.com/evilguest/
Дата: 13.02.20 04:19
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

S>>С точки зрения HTTP, совершенно неважно, что там происходит "на сервере". Важно то, как мы это представляем клиенту. Representational State Transfer. Если клиенту выставляется такая модель ресурсов, что при применении этого действия к модели добавляется новый ресурс, то делаем через PUT.

S>>На всякий случай поясню, что такие вопросы обсуждать бессмысленно. Конструктивную беседу можно вести только в рамках более-менее очерченной задачи.
S>>Придумай задачу, для которой тебе кажется естественным некий RPC-API (можешь сразу и набросать его черновик), а REST-API вызывает затруднения. Я покажу, как сделать REST для этой задачи, и можно будет сравнить достоинства и недостатки.

PD>Пожалуйста. Сразу прошу прощения за небольшие отклонения от классика , сделаны для пущей выразительности.

PD>Так что же это — POST, PUT или DELETE ? И чего именно ?
Ага. Вижу, набросать RPC вариант сходу не удалось. Лучше бы, конечно, состряпать инженерную задачу, а не Гоголя цитировать, но даже так подойдёт.
Ладно, в REST это будет PUT ресурса "персона".
В RPC у нас сразу возникают вопросы:
— что, если вызов вашего метода так и не вернул ничего? Что нам делать дальше?
— Нужно ли пробовать его ещё раз, и если да, то где гарантия, что по городу не начнут бродить N ревизоров одновременно?

PD>COM работает в условиях локальной машины, а DCOM — это Distributed COM, работает в локальной сети.

Я в курсе.
S>>Использовать DCOM через океан — упаси байт! Представь себе приложение резервирования авиабилетов, написанное на DCOM. Или хотя бы онлайн-регистрации. Нафиг-нафиг.
PD>Причин же, почему DCOM для этого не используется , три
PD>1. HTTP был сделан раньше, вот его и продолжвли использовать
PD>2. COM нет в линуксе, что сразу ставит крест на возможности его использования для этой цели
PD>3. COM не подерживают все браузеры даже в Windows.
Ок, попробую объяснить помедленнее. Отбросим вопрос с браузером. Предположим, мы пишем с нуля систему типа aviasales.ru. Сервер — на винде (мы выбираем, так что можем ставить всё, что захотим). Клиенты — десктопное приложение на винде.
Можно попробовать работать в одном из очевидных стилей:
1. Пишем локальное приложение. Клиенты заходят по RDP и запускают его на сервере терминалов.
3. Пишем клиент-сервер на SQL. Клиенты подключаются прямо к СУБД по 1433
2. Пишем трёхзвенку на DCOM
3. Пишем трёхзвенку на REST
Как ты думаешь, какой из стилей обеспечит лучшую масштабируемость, надёжность, и стоимость внесения изменений при одинаковом железе?
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[14]: REST: прохой\хороший интерфейс
От: Pavel Dvorkin Россия  
Дата: 13.02.20 04:37
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>Ага. Вижу, набросать RPC вариант сходу не удалось.


Нет, просто забыл. Добавил там.

Лучше бы, конечно, состряпать инженерную задачу, а не Гоголя цитировать, но даже так подойдёт.
S>Ладно, в REST это будет PUT ресурса "персона".

Хм, а почему же PUT ? Может , все же POST ? Ведь не было же там его, что же меняем ?

S>В RPC у нас сразу возникают вопросы:

S>- что, если вызов вашего метода так и не вернул ничего? Что нам делать дальше?
S>- Нужно ли пробовать его ещё раз, и если да, то где гарантия, что по городу не начнут бродить N ревизоров одновременно?

А он и не должен ничего возвращать. В данной версии не предусмотрено, это что-то вроде UDP, потому что в Ревизоре ничего толком не сказано о том, кто посылает (туманное именное повеление — вот и все). Если же нужно — метод должен выбросить исключение, и автор именного повеления примет решение, что делать. Например, если было исключение RevisorKilledException, то, возможно, надо послать туда следователей

S>Ок, попробую объяснить помедленнее. Отбросим вопрос с браузером. Предположим, мы пишем с нуля систему типа aviasales.ru. Сервер — на винде (мы выбираем, так что можем ставить всё, что захотим). Клиенты — десктопное приложение на винде.

S>Можно попробовать работать в одном из очевидных стилей:
S>1. Пишем локальное приложение. Клиенты заходят по RDP и запускают его на сервере терминалов.
S>3. Пишем клиент-сервер на SQL. Клиенты подключаются прямо к СУБД по 1433
S>2. Пишем трёхзвенку на DCOM
S>3. Пишем трёхзвенку на REST
S>Как ты думаешь, какой из стилей обеспечит лучшую масштабируемость, надёжность, и стоимость внесения изменений при одинаковом железе?

Первое и второе обсуждать незачем.
А вот третье и четвертое — зависит от того, насколько качественно будет реализовано.
With best regards
Pavel Dvorkin
Re[14]: REST: прохой\хороший интерфейс
От: Буравчик Россия  
Дата: 13.02.20 06:19
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>Даже напрячься не успеем.

S>
S>GET /calculate?expression=((1800*999)-677)/65866556
S>


А если мы делаем "платный прогноз погоды"?
Пользователю доступно не более 10 запросов в месяц.
Операции: getWeather (получение погоды) и getStats (количество неиспользованных запросов)
Best regards, Буравчик
Re[15]: REST: прохой\хороший интерфейс
От: Sinclair Россия https://github.com/evilguest/
Дата: 13.02.20 06:50
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

PD>Хм, а почему же PUT ? Может , все же POST ? Ведь не было же там его, что же меняем ?

Потому, что с PUT нам проще обеспечить идемпотентность. Ненадёжная RPC-реализация, очевидно, предложена не от глубокого понимания ограничений задачи, а просто от некомпететности.
REST-реализация позволяет нам решить проблему двух генералов: в случае потери коммуникации мы будем отправлять туда ревизора столько раз, сколько потребуется — и иметь гарантию его единственности:
PUT /person/12123743120912312
If-None-Match: * 

{
 "наружность": "недурная",
 "платье": "партикулярное",
 ...
}

Проблемы с POST уже описаны в параллельной ветке: https://rsdn.org/forum/design/7653493.1
Автор: Sinclair
Дата: 10.02.20


PD>А он и не должен ничего возвращать. В данной версии не предусмотрено, это что-то вроде UDP, потому что в Ревизоре ничего толком не сказано о том, кто посылает (туманное именное повеление — вот и все).

Прекрасно, Павел. С тем же успехом можно просто писать в dev/null — ведь
а) предлагаемый вами метод имеет тип void, т.е. результат не нужен
б) механизмов контроля того, что вызов произвёл хоть какие-то побочные эффекты, тоже не предусмотрено.
А раз клиента это устраивает — чего и огород городить? Сервер какой-то писать. dev/null полностью удовлетворяет заданной спецификации, и требует 0 затрат на разработку и поддержку.
Нет, надо что-то ещё? Ну так значит садитесь и изобретайте ключи идемпотентности, политику retry. Придумывайте, как вы будете оповещать клиентов о миграции ендпоинта на новый адрес.
Что делать, если придёт запрос с тем же ключом идемпотентности, но с другим содержимым.
RPC провоцирует людей делать стрёмные протоколы. Причём если в REST, к примеру, архитектор и девелопер тупили и сделали первую версию криво, то вторую можно просто починить.
То есть не меняем спецификацию протокола, а меняем поведение — с некорректного на корректное. И всё, всё начинает работать.
В RPC придётся менять сигнатуры методов, а это очень, очень дорогое удовольствие.
Вам ещё повезёт, если вместо убогого DCOM был выбран какой-то более гибкий RPC протокол, например XML-RPC. Там хотя бы можно добавлять к существующим вызовам необязательные параметры, сохраняя обратную совместимость.
А с DCOM или классическим RPC проект умрёт ещё до выхода в продакшн.

PD>Если же нужно — метод должен выбросить исключение, и автор именного повеления примет решение, что делать. Например, если было исключение RevisorKilledException, то, возможно, надо послать туда следователей

Вот она, ущербность RPC-мышления в полный рост. Привычка к гарантии того, что исключение достигнет соответствующего catch-блока, взятая из локальных вызовов процедур.
Сеть устроена не так — метод-то может что-то и выкинет, но далеко не факт, что клиент что-то поймает. Ревизора убили, в городе война с турками, казна разворована на взятки.
Ни о чём из этого клиент не узнаёт — просто вызов получил в ответ RPC_E_TIMEOUT.

S>>1. Пишем локальное приложение. Клиенты заходят по RDP и запускают его на сервере терминалов.

S>>3. Пишем клиент-сервер на SQL. Клиенты подключаются прямо к СУБД по 1433
S>>2. Пишем трёхзвенку на DCOM
S>>3. Пишем трёхзвенку на REST
S>>Как ты думаешь, какой из стилей обеспечит лучшую масштабируемость, надёжность, и стоимость внесения изменений при одинаковом железе?

PD>Первое и второе обсуждать незачем.

PD>А вот третье и четвертое — зависит от того, насколько качественно будет реализовано.
Вспотеешь ты "качественно реализовывать" DCOM. Построить REST-сервер, который обслуживает пару десятков тысяч клиентов одновременно, можно не выходя из режима "скопировал демку со stackoverflow".
DCOM-сервер будет дохнуть на нагрузках примерно в тысячу раз меньше. Нет, его можно будет подпилить так, чтобы проигрыш был всего на порядок, но к этому моменту бюджет уже закончится.
Это в предположении, что архитектор был настолько квалифицирован, что сумел сразу предусмотреть все механизмы кэширования, восстановления после сбоев, обработки конфликтов и прочего — что в REST идёт из коробки.
В обычном случае получим многопользовательскую систему на 10-100 пользователей, и любые попытки масштабировать её хотя бы в 100 раз приведут к выбросу и замене на веб-приложение.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[15]: REST: прохой\хороший интерфейс
От: Sinclair Россия https://github.com/evilguest/
Дата: 13.02.20 06:52
Оценка:
Здравствуйте, Буравчик, Вы писали:
Б>А если мы делаем "платный прогноз погоды"?
Б>Пользователю доступно не более 10 запросов в месяц.
Б>Операции: getWeather (получение погоды) и getStats (количество неиспользованных запросов)
GET /weather

GET /stats

Что именно вызывает затруднения?
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[16]: REST: прохой\хороший интерфейс
От: night beast СССР  
Дата: 13.02.20 07:00
Оценка:
Здравствуйте, Sinclair, Вы писали:

Б>>А если мы делаем "платный прогноз погоды"?

Б>>Пользователю доступно не более 10 запросов в месяц.
Б>>Операции: getWeather (получение погоды) и getStats (количество неиспользованных запросов)
S>GET /weather

здесь request_id не нужен?
Re[17]: REST: прохой\хороший интерфейс
От: Sinclair Россия https://github.com/evilguest/
Дата: 13.02.20 07:09
Оценка:
Здравствуйте, night beast, Вы писали:
NB>здесь request_id не нужен?
Вот недостаточно данных. Потому что непонятно, как подсчитывать количество запросов в месяц: считать ли "одинаковые" результаты "разными" запросами, или одним и тем же?
Если разными, то считаем ли мы 304 за такой запрос, или нет?
Что заставляет пользователя повторять запросы — там меняются какие-то параметры, или меняется сама погода?

Обычно подобные ограничения на API ставят на стороне сервера; плохая коммуникация считается проблемой клиента. Просто при превышении лимита клиент получает 503 с соответствующим Retry-After, а злонамеренное игнорирование Retry-After приводит к бану аккаунта.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[16]: REST: прохой\хороший интерфейс
От: Буравчик Россия  
Дата: 13.02.20 07:16
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>Что именно вызывает затруднения?


Хм... Проблема в сбоях во время вызова weather — сервер запрос отработал, а клиент ответ не получил.
Пользователь будет повторять свой запрос и ему придется платить заново.
Best regards, Буравчик
Re[17]: REST: прохой\хороший интерфейс
От: Sinclair Россия https://github.com/evilguest/
Дата: 13.02.20 07:42
Оценка:
Здравствуйте, Буравчик, Вы писали:
Б>Хм... Проблема в сбоях во время вызова weather — сервер запрос отработал, а клиент ответ не получил.
Б>Пользователь будет повторять свой запрос и ему придется платить заново.
Да, GET подразумевает safe-семантику, т.е. изменением состояния сервера можно пренебречь.
При проектировании сервиса придётся принимать во внимание конкурирующие соображения: GET удобен с точки зрения сценария использования и возможностей кэширования.

В общем, если нам страшно потерять деньги (или выдать лишний ответ), то придётся по-честному выставлять управляемое состояние — то есть будет история "запросов погоды", будет правило "не больше 10 за 31 день" или ещё как-то, будут PUT, будут последующие GET.

Если же суперточность биллинга не принципиальна, и лимиты там не 10 в месяц, а 1000 в день, то работаем одним из следующих способов:
1. Пост-ограничение. Клиент, который шарашит нас большим количеством запросов, получает счёт за превышение лимита, или ему временно усиливают throttling.
2. Уточнение подсчётов — обучаемся отличать повторы "одного и того же" запроса от "новых" запросов, за "одинаковые" лимит не трогаем.

Встречный вопрос — а что нам предлагает RPC?
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[18]: REST: прохой\хороший интерфейс
От: TG  
Дата: 13.02.20 08:03
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>2. Уточнение подсчётов — обучаемся отличать повторы "одного и того же" запроса от "новых" запросов, за "одинаковые" лимит не трогаем.


И тут уже requestId нужен, да?
Re[19]: REST: прохой\хороший интерфейс
От: Sinclair Россия https://github.com/evilguest/
Дата: 13.02.20 08:50
Оценка:
Здравствуйте, TG, Вы писали:
TG>И тут уже requestId нужен, да?
Он одновременно не нужен и недостаточен. Мы же не хотим, чтобы хитрый клиент просто использовал 100 раз в месяц 1 RequestID
Так что без деталей я спроектировать API не могу.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[15]: REST: прохой\хороший интерфейс
От: · Великобритания  
Дата: 13.02.20 09:21
Оценка:
Здравствуйте, samius, Вы писали:

S>>>Влезу. Ну, например, калькулятор, который на удаленной машине чего-то считает. rpc прямолинеен, а вот с rest придется попотеть. Вообще, как я понимаю, rest нужен, когда мы имеем дело

...
S>То есть, по-крайней мере название REST — это о том, как клиент хранит состояние сессии. Но, конечно, REST не ограничивается одной лишь этой идеей, в списке идей источников присутствует Remote Session.
Не совсем понятно к чему ты это говоришь. Какое состояние сессии в рассматриваемом примере калькулятора? Ведь тут не нужно никаких сессий, тривиальный запрос-ответ, никакого состояния репрезентить не надо.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[16]: REST: прохой\хороший интерфейс
От: Sharov Россия  
Дата: 13.02.20 10:14
Оценка:
Здравствуйте, ·, Вы писали:

·>Здравствуйте, Sharov, Вы писали:


S>>·>Калькулятор это stateless — скучно и тривиально, решается одинаково просто практически на чём угодно левой пяткой во сне. А REST это всё-таки Representational state transfer.

S>>Нам не нужен state, я же написал об этом. Нам нужны выч. ресурсы -- закинул задачу и пошел себе дальше.
·>Т.е. код примерно такой:
·>
·>try
·>{
·>    result = remote.calculator(expression);
·>}
·>catch(RemoteException e) {
·>    //do what??
·>}
·>

·>Вот уже надо как-то отличать типы RemoteException чтобы либо показать пользователю "у вас тут что-то не так" или "сервер занят. Повторить?".

А в http rest на отиличать не надо?

·>Да, я ещё там в своё сообщение параграф вставил, ты видимо не заметил.


Видел, но я не спорю что лучше. Я к тому, что все-таки есть сценарии, где rpc подходит больше\лучше.
Кодом людям нужно помогать!
Re[14]: REST: прохой\хороший интерфейс
От: Sharov Россия  
Дата: 13.02.20 10:58
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>Здравствуйте, Sharov, Вы писали:


S>>Влезу. Ну, например, калькулятор, который на удаленной машине чего-то считает. rpc прямолинеен, а вот с rest придется попотеть.

S>Даже напрячься не успеем.
S>
S>GET /calculate?expression=((1800*999)-677)/65866556
S>

S>Более интересный пример:
S>
S>GET /factor?number=568132681318943132168430
S>


1) Слишком большое выражение мы посчитать не сможем из-за ограничения на длину query. Впрочем, я проверил, но и wolframalpha работает через rest.
2) Технологически это не критично. А вот семанткика get тут не понятна. Get возвращает некоторые ресурсы. Но существует ли такой ресурс (как подмно-во других)
calculate?expression=((1800*999)-677)/65866556 на сервере? Т.е. в данной задаче мы ломаем rest, который post превращает в get. Нет у нас такой задачи(ресурса),
поэтому неверно для нее делать get. Тут уж скорее post. Корявый тут rest получается. И опять же то ли в этой дискуссии, то ли в другой недавно прибегали ссылкы на
дизайн rest api. И там очень советовали не включать глаголы типа calculate, factor и т.д. в api. Что Вы тут же и сделали. Что говорит о том, что это не rest задача.
Т.е. можно, но ломая rest через колено.


S>Вообще, как я понимаю, rest нужен, когда мы имеем дело

S>>с необходимостью CRUD чего-то. Если нам просто нужны чьи-то выч. ресурсы и время, без соотв. crud, то rpc вполне подойдет.
S>REST нужен тогда, когда мы работаем с разделяемым состоянием.

А что такое разделяемое состояние -- подмножество всех состояний, которое хранится у данного клиента или что?
Кодом людям нужно помогать!
Re[4]: REST: прохой\хороший интерфейс
От: Serginio1 СССР https://habrahabr.ru/users/serginio1/topics/
Дата: 13.02.20 11:05
Оценка:
Здравствуйте, Sinclair, Вы писали:

Антон привет!
Что скажешь по gRPC
https://habr.com/ru/company/infopulse/blog/265805/

Именно с этого места и начинается gRPC. Итак, из коробки мы имеем:
Protobuf в качестве инструмента описания типов данных и сериализации. Очень классная и хорошо зарекомендовавшая себя на практике штука. Собственно говоря, те, кому была нужна производительность — и раньше брали Protobuf, а дальше уже отдельно заморачивались транспортом. Теперь всё в комплекте.
HTTP/2 в качестве транспорта. И это невероятно мощный ход! Вся прелесть полного сжатия данных, контроля трафика, инициации событий с сервера, переиспользования одного cокета для нескольких параллельных запросов — красотища.
Статические пути — никаких больше «сервис/коллекция/ресурс/запрос? параметр=значение». Теперь только «сервис», а что внутри — описывайте в терминах вашей модели и её событий.
Никакого привязывания методов к HTTP-методам, никакого привязывания возвращаемых значений к HTTP-статусам. Пишите, что хотите.
SSL/TLS, OAuth 2.0, аутентификация через сервисы Google, плюс можно прикрутить свою (например, двухфакторную)
Поддержка 9-ти языков: C, C++, Java, Go, Node.js, Python, Ruby, Objective-C, PHP, C# плюс, конечно, никто не запрещает взять и реализовать свою версию хоть для брейнфака.
Поддержка gRPC в публичных API от Google. Уже работает для некоторых сервисов. Нет, REST-версии, конечно, тоже останутся. Но посудите сами, если у вас будет выбор — использовать, скажем, из мобильного приложения REST-версию, отдающие данные за 1 сек или с теми же затратами на разработку взять gRPC-версию, работающую 0.5 сек — что вы выберете? А что выберет ваш конкурент?


https://docs.microsoft.com/ru-ru/aspnet/core/tutorials/grpc/grpc-start?view=aspnetcore-3.1&amp;tabs=visual-studio
и солнце б утром не вставало, когда бы не было меня
Отредактировано 13.02.2020 11:08 Serginio1 . Предыдущая версия .
Re[16]: REST: прохой\хороший интерфейс
От: Sharov Россия  
Дата: 13.02.20 11:08
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>Здравствуйте, Sharov, Вы писали:

S>>Нам не нужен state, я же написал об этом. Нам нужны выч. ресурсы -- закинул задачу и пошел себе дальше.
S>Вот прямо отличный пример. "Пошёл себе дальше" подразумевает, наверное, возможность как-то потом забрать результат, так?
S>Значит, у нас появляется сущность "задача", и её состояние: "в очереди", "в процессе выполнения", "выполнена", "сбой выполнения". Это состояние нужно синхронизовывать между клиентом и сервером.
S>Всё, REST начинает выигрывать у RPC ещё до начала забега — как раз потому, что он позволяет внятно описать CRUD над множеством задач. Ваши первые две-три реализации RPC будут страдать от детских болезней вроде "нечаянно поставил одну и ту же задачу в очередь дважды" или "задачу поставил — результат потерял".

Нет никакогов выигрыша. У нас запрос-ответ. Есть состояние на короткий интервал времени, причем от силы один глагол от всего rest(crud). Т.е. rpc не то что не позволяет crud, а он тут особо не нужен.
Вместо и взять и посчитать, мы разводим философию в стиле апорий Зенона. А результат можно забрать и polling'ом и по дуплексу(callback).
Кодом людям нужно помогать!
Re[16]: REST: прохой\хороший интерфейс
От: Pavel Dvorkin Россия  
Дата: 13.02.20 11:22
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>Потому, что с PUT нам проще обеспечить идемпотентность. Ненадёжная RPC-реализация, очевидно, предложена не от глубокого понимания ограничений задачи, а просто от некомпететности.


Нет, Антон. Причина тут другая — ты просто почувствовал, что POST, в результате которого делаются некие удаления (гусей с гусенками) и изменения (состояния Держиморды) — это как-то не комильфо. Вот и пытаешься использовать некий PUT , дескать это какое-то изменение общего плана, куда и удаление и изменение прицепить можно.

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

Вот это и есть натягивание всех сложных ситуаций самых разных приложений на пресловутую модель POST/PUT/GET/DELETE, созданную изначально для простого оперирования ресурсами.


PD>>А он и не должен ничего возвращать. В данной версии не предусмотрено, это что-то вроде UDP, потому что в Ревизоре ничего толком не сказано о том, кто посылает (туманное именное повеление — вот и все).

S>Прекрасно, Павел. С тем же успехом можно просто писать в dev/null — ведь
S>а) предлагаемый вами метод имеет тип void, т.е. результат не нужен

Ну это дело вкуса. В гоголевском Ревизоре он и впрямь не нужен. Если же нужен

Report addPerson(Person);

S>б) механизмов контроля того, что вызов произвёл хоть какие-то побочные эффекты, тоже не предусмотрено.


Можно поинтересоваться, какие механизмы контроля есть в обычном LPC ? Например, при добавлении картинки на холст ?

S>А раз клиента это устраивает — чего и огород городить? Сервер какой-то писать. dev/null полностью удовлетворяет заданной спецификации, и требует 0 затрат на разработку и поддержку.


Нет, не устраивает, ибо гуси с гусенками не будут удалены, а Держиморда будет по-прежнему махать кулаками.

S>В RPC придётся менять сигнатуры методов, а это очень, очень дорогое удовольствие.


Я тебе небольшой секрет открою — в обычном десктопном приложении тоже придется. Тем не менее я что-то не вижу желания прикрутить HTTP, скажем, в десктопных приложениях

S>Вам ещё повезёт, если вместо убогого DCOM был выбран какой-то более гибкий RPC протокол, например XML-RPC. Там хотя бы можно добавлять к существующим вызовам необязательные параметры, сохраняя обратную совместимость.

S>А с DCOM или классическим RPC проект умрёт ещё до выхода в продакшн.

Да, необязательные параметры — это хорошо. В thrift они, впрочем, есть.

PD>>Если же нужно — метод должен выбросить исключение, и автор именного повеления примет решение, что делать. Например, если было исключение RevisorKilledException, то, возможно, надо послать туда следователей

S>Вот она, ущербность RPC-мышления в полный рост. Привычка к гарантии того, что исключение достигнет соответствующего catch-блока, взятая из локальных вызовов процедур.

Нет, Антон. Оно таки в thrift достигнет. Всегда. В крайнем случае получишь TTransportException, если что-то не будет передано. И, разумеется, любой клиент должен быть готов к этому TTransportException

https://www.javatips.net/api/org.apache.thrift.transport.ttransportexception


S>Сеть устроена не так — метод-то может что-то и выкинет, но далеко не факт, что клиент что-то поймает. Ревизора убили, в городе война с турками, казна разворована на взятки.

S>Ни о чём из этого клиент не узнаёт — просто вызов получил в ответ RPC_E_TIMEOUT.

Тоже TTransportException, если задать таймаут.



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

S>Это в предположении, что архитектор был настолько квалифицирован, что сумел сразу предусмотреть все механизмы кэширования, восстановления после сбоев, обработки конфликтов и прочего — что в REST идёт из коробки.
S>В обычном случае получим многопользовательскую систему на 10-100 пользователей, и любые попытки масштабировать её хотя бы в 100 раз приведут к выбросу и замене на веб-приложение.

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

Вот этот тезис я принимаю. Но этот факт не отменяет того, что для реализации этого стандарта был выбран инструмент, изначально заточенный для других, более простых задач, в результате чего его допиливали и натягивали на эти задачи. Вместо того, чтобы предложить иной протокол, более адекватный для современных приложений. А как его реализовать — вопрос десятый. Можно и поверх RPC, можно и просто поверх TCP/IP. RPC-то тоже через TCP/IP работает.

Если хочешь — вот тебе такое сравнение. HTTP — это MS-DOS, расширенная и модифицированная до Windows 9x. Простенькая однопользовательская ОС, которую довели до многопользовательского и многопоточного режима, да еще GUI прикрутили и тот же DCOM/OLE/RPC. Работала же, вполне.
А Windows NT пока не видать, да, скорее всего, увы, и не будет.
With best regards
Pavel Dvorkin
Re[15]: REST: прохой\хороший интерфейс
От: Sinclair Россия https://github.com/evilguest/
Дата: 13.02.20 12:35
Оценка:
Здравствуйте, Sharov, Вы писали:
S>1) Слишком большое выражение мы посчитать не сможем из-за ограничения на длину query.
Может быть, это и хорошо? Системы проектируют под реальные требования, а не под абстрактные капризы.
Если в вашей задаче "параметром" ресурса становится слишком длинная строка — да, придётся приседать. Но это бывает а) редко, б) обходится нетрудно.

S>2) Технологически это не критично. А вот семанткика get тут не понятна. Get возвращает некоторые ресурсы. Но существует ли такой ресурс (как подмно-во других)

S>calculate?expression=((1800*999)-677)/65866556 на сервере? Т.е. в данной задаче мы ломаем rest, который post превращает в get. Нет у нас такой задачи(ресурса),
S>поэтому неверно для нее делать get.
Вы неправильно понимаете rest. Этот ресурс, конечно же, есть, и мы ничего не "ломаем".
REST совершенно не обязывает вас ограничиваться только "реально существующими" ресурсами, или даже конечным их списком.
Вот, к примеру, таблица умножения — совершенно необязательно хранить её на сервере. Можно её вычислять — но клиенту-то всё равно!
У него создаётся иллюзия того, что на сервере "хранится" практически бесконечная таблица умножения. Зачем ему отличать "вычисленные" ресурсы от "реальных"?

S>Тут уж скорее post. Корявый тут rest получается. И опять же то ли в этой дискуссии, то ли в другой недавно прибегали ссылкы на

S>дизайн rest api. И там очень советовали не включать глаголы типа calculate, factor и т.д. в api. Что Вы тут же и сделали. Что говорит о том, что это не rest задача.
Можно ссылку на эти рекомендации? Может, я что-то упустил.
S>Т.е. можно, но ломая rest через колено.
Нет. Вы неверно понимаете REST.

S>>REST нужен тогда, когда мы работаем с разделяемым состоянием.

S>А что такое разделяемое состояние -- подмножество всех состояний, которое хранится у данного клиента или что?
Это такое состояние, работа над которым ведётся совместно. Например, данный форум ценен именно тем, что наполнение форумов делается большим количеством участников. И у них есть согласованное представление о том, как устроены дискуссии — кто, когда, что, и на что отвечает.
Если бы мы отключили от форума всех участников, кроме вас, то вы могли бы скопировать его состояние (реплику базы) к себе, и править её локально любым удобным для вас образом. Соображения всяких идемпотентностей и кэширования были бы нерелевантны, т.к. был бы устранён ненадёжный и медленный канал между вами и состоянием системы.

Случай с "сервисом вычислений", когда вроде бы других пользователей, вмешивающихся в очередь заданий нету, тоже подходит под разделяемое состояние — на этот раз есть "пользователь", который ставит задачи и получает результаты, и "агент" — автомат, который решает вычислительные задачи и предоставляет их результаты.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[5]: REST: прохой\хороший интерфейс
От: Sinclair Россия https://github.com/evilguest/
Дата: 13.02.20 12:36
Оценка:
Здравствуйте, Serginio1, Вы писали:

S> Что скажешь по gRPC

S>https://habr.com/ru/company/infopulse/blog/265805/
Надо читать. Выглядит подозрительно.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[17]: REST: прохой\хороший интерфейс
От: Sinclair Россия https://github.com/evilguest/
Дата: 13.02.20 12:47
Оценка:
Здравствуйте, Sharov, Вы писали:
S>Нет никакогов выигрыша. У нас запрос-ответ. Есть состояние на короткий интервал времени, причем от силы один глагол от всего rest(crud). Т.е. rpc не то что не позволяет crud, а он тут особо не нужен.
S>Вместо и взять и посчитать, мы разводим философию в стиле апорий Зенона. А результат можно забрать и polling'ом и по дуплексу(callback).
Какой-то мухлёж пошёл. Если можно "просто взять и посчитать", то нафига вам вообще сервис? Берите и считайте.
А если у вас вычислительно тяжёлая задача, то одно из двух:
1. Она тяжелая локально, а удалённый сервис умеет её исполнять гарантированно мгновенно (по сравнению со временем передачи туда-обратно). Ну, например, квантовый факторизатор длинных целых.
Тогда делаем ровно GET с параметрами.
2. Она тяжелая в любом случае, но мы не хотим гонять локальный CPU при 100% восемь часов. А хотим получить результат асинхронно через полчаса.
Я ваше "закинул и пошёл дальше" воспринимаю именно как п.2.
Чтобы что-то поллить или callback-ать, надо сначала убедиться, что есть что поллить.

В REST как раз всё это есть — сделали PUT, он нам сказал 201 Сreated, и мы делаем GET на него с удобной нам периодичностью.
Если мы получили таймаут или 5хх, то у нас есть детерминированный способ понять, встала ли всё же задача в очередь, и если не встала, то как её поставить без риска задвоить задание и сжечь вдвое больше денег.

GET нам отдаёт 304 с пустым телом до тех пор, пока статус задачи не изменится — после этого приедет 200 Ok вместе с нужным нам результатом. Результат может внезапно оказаться большим — например, "вычислительная задачка" была 4K-рендером получасового ролика с компрессией в H.264. И теперь мы будем сливать все эти гигабайты — о щастье, что в HTTP уже предусмотрен Range header, что даст нам возможность продолжать закачку при обрыве связи. Более того, лёгким движением руки перед рендер-фермой ставится ферма из дешёвых reverse proxy. Когда я начинаю качать этот фильм по своему GPRS-каналу, прокси быстро скачивает весь контент к себе по 10G Ethernet, и последующие запросы "ой, у меня тут связь пропала, можно я с 68 мегабайта продолжу" вообще не отвлекают рендер-ферму от работы.
В RPC вам всё это придётся колхозить с нуля из говна и палок.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[17]: REST: прохой\хороший интерфейс
От: Sinclair Россия https://github.com/evilguest/
Дата: 13.02.20 13:02
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

PD>Нет, Антон. Причина тут другая — ты просто почувствовал, что POST, в результате которого делаются некие удаления (гусей с гусенками) и изменения (состояния Держиморды) — это как-то не комильфо. Вот и пытаешься использовать некий PUT , дескать это какое-то изменение общего плана, куда и удаление и изменение прицепить можно.

Павел, я же говорил — психология тут ни причём. Не надо придумывать какие-то "чувства".
PD>Если бы тут никакого ревизора не было, а просто надо было бы вновь приехавашего добавить в книгу проезжающих — POST классический.
Нет. POST — это самый плохой из всех HTTP глаголов, т.к. он предоставляет минимум гарантий. Чтобы его использовать, нужны веские причины.
PD>Ну это дело вкуса. В гоголевском Ревизоре он и впрямь не нужен. Если же нужен

PD>Report addPerson(Person);

PD>Можно поинтересоваться, какие механизмы контроля есть в обычном LPC ? Например, при добавлении картинки на холст ?
В обычном LPC эти механизмы и не нужны — там не бывает ситуации типа "мы не знаем, удалось ли нам сделать вызов, или нет". Даже если между caller и callee возникла коммуникационная проблема (переполнился стек, ну или адрес вызова оказался булшитом), то мы получаем вполне внятное исключение. В RPC нет такой роскоши.
PD>Нет, не устраивает, ибо гуси с гусенками не будут удалены, а Держиморда будет по-прежнему махать кулаками.
Павел, ты мухлюешь. Вот у нас есть клиент — то самое неопределённое лицо. Вот оно в чём заинтересовано? Ставит ли оно задачу удалить гусей с гусёнками? Или оно просто отправляет ревизора — а как там будет обрабатываться его появление, уже дело местных властей?

PD>Я тебе небольшой секрет открою — в обычном десктопном приложении тоже придется. Тем не менее я что-то не вижу желания прикрутить HTTP, скажем, в десктопных приложениях

Пввел, нужно быть очень, очень мотивированным, чтобы не видать этого желания. Вот, например, весь микрософт офис теперь насквозь прикручен к HTTP. Пытаешься сохранить документ — а он тебе "ну давай его в шарепоинт зальйом!". А шарепоинт — это WebDAV, чистый незамутнённый REST. Хочешь отправить документ коллеге — то же самое.
Ты покажи мне десктопное приложение, которое работает с разделяемым состоянием — 90 против 1, что оно ходит на сервер по http.

PD>Нет, Антон. Оно таки в thrift достигнет. Всегда. В крайнем случае получишь TTransportException, если что-то не будет передано. И, разумеется, любой клиент должен быть готов к этому TTransportException


PD>https://www.javatips.net/api/org.apache.thrift.transport.ttransportexception

Не верю. Чудес не бывает. Никакими ексепшнами ты проблему двух генералов не решишь.

PD>Тоже TTransportException, если задать таймаут.

Ну, и? Как мне понять, где произошёл transportException — на этапе передачи запроса, или на этапе передачи ответа?
Вот я делаю placeOrder() — как сделать так, чтобы гарантированно разместить не более 1 заказа, при условии ненадёжности сети?

PD>Вот этот тезис я принимаю. Но этот факт не отменяет того, что для реализации этого стандарта был выбран инструмент, изначально заточенный для других, более простых задач, в результате чего его допиливали и натягивали на эти задачи. Вместо того, чтобы предложить иной протокол, более адекватный для современных приложений. А как его реализовать — вопрос десятый. Можно и поверх RPC, можно и просто поверх TCP/IP. RPC-то тоже через TCP/IP работает.


PD>Если хочешь — вот тебе такое сравнение. HTTP — это MS-DOS, расширенная и модифицированная до Windows 9x. Простенькая однопользовательская ОС, которую довели до многопользовательского и многопоточного режима, да еще GUI прикрутили и тот же DCOM/OLE/RPC. Работала же, вполне.

PD>А Windows NT пока не видать, да, скорее всего, увы, и не будет.
Да всё наоборот. RPC — это протокол для примитивных задач, типа "сделать что-то, не пойми что". А HTTP делался для сложных задач — как обеспечить быструю и надёжную репликацию состояния, а также согласование протоколов между клиентом и сервером. Там очень много есть про graceful degradation — это позволяет что клиенту, что серверу начинать с очень дешёвой и простой реализации, а по мере роста потребностей развивать её независимо с обеих сторон.
Например, инкрементальности передачи в RPC нету — примитив же, просто "байты по сети". Он лишь чуть лучше, чем голый TCP-стрим. А в HTTP инкрементальность заложена в сам протокол. При этом сервер не обязан её поддерживать — можно запустить proof of concept без неё, и все клиенты и прокси прекрасно будут с твоим сервером работать. Потом прикручиваешь инкрементальность — и все существующие клиенты продолжают работать. А те из них, которые умеют инкрементальность, получают преимущество в тот же момент.
Или компрессию.
Причём у тебя один и тот же протокол могут отдавать три сервера — в одном есть инкрементальная передача, в другом компрессия, в третьем и то и другое. И клиенты будут прекрасно работать со всеми тремя.
В RPC протоколе эта задача потребует настолько адских приседаний, что шансов получить под них бюджет очень мало.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[19]: REST: прохой\хороший интерфейс
От: Sinclair Россия https://github.com/evilguest/
Дата: 13.02.20 13:31
Оценка:
Здравствуйте, Буравчик, Вы писали:

Б>Передачу ключей идемпотентности, как и REST. И нужно явно позаботиться об этом, как и в REST.

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

Б>Интересно, что при проектировании приложения ты используешь анемик (ФП-стиль), но при проектировании API действуешь с точность до наоборот.

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

>Рассматривая соседнюю тему о расчете надбавки, вероятно, в API появидсяся бы ресурс "рассчитать надбавку" (ок, просто "надбавка").

Б>Но это и есть RPC-стиль, о котором я говорил выше. Работа от операций, а не от ресурсов.
Неа. Анемик как раз прекрасно ложится на REST — и наоборот.
Нет у нас никакого "рассчитать надбавку".
Есть просто GET /{resellerId}/prices — который умеет всё, что нужно типа conditional get, range header (с кастомными юнитами), а при необходимости и delta encoding.
На стороне сервера он стреляет в анемичный контроллер, который имеет доступ к DbContext, и подтаскивает список товаров вместе с применимыми к ним правилами формирования наценок.
Там прекрасно работает декомпозиция — например, мы можем вынести работу с правилами ценообразования в отдельный класс, которым будем пользоваться как из модуля "показ прайслиста", так и из модуля "обработки заказа".

"операция" в том смысле, который более-менее похож на RPC — это отправка заказа.
В зависимости от того, насколько я доверяю авторам клиентской части, я бы делал его либо через PUT, либо через POST.
При наличии выбора — естественно, через PUT.
Потому что у меня будет возможность обработать массу ситуаций предсказуемым образом. POST потребует дополнительных усилий, которые есть риск забыть сделать
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[17]: REST: прохой\хороший интерфейс
От: Sinclair Россия https://github.com/evilguest/
Дата: 13.02.20 13:37
Оценка:
Здравствуйте, Sharov, Вы писали:

S>А в http rest на отиличать не надо?

В HTTP у нас есть штатный способ.
200 Ok — всё в порядке
4xx — проблема с вашим запросом; повторять его нет смысла, пока вы не исправите проблему.
Подробности описываются кодом статуса + телом ответа.
5хх — проблема сервера; запрос, возможно, удастся повторить позже (+Retry-After, если известно, насколько позже).
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[19]: REST: прохой\хороший интерфейс
От: Ватакуси Россия  
Дата: 13.02.20 14:41
Оценка:
В>>И если одназночность так и не пришла, валить сервер DDOS-ом?
S>Откуда D DOS? Вы всё же в словаре-то смотрите незнакомые слова, прежде чем ими пользоваться
Телепат в студии? Откуда известно что и кому неизвестно?
Клиенты всегда сидят на одном и том же компьютере, сетке, городе, стране, планете? Да, всегда, но вполне могут быть распределены.

S>1. Со стороны сервера, вам в любом случае нужно думать о throttling. Потому что нет никакой гарантии, что клиенты ведут себя прилично, и не захотят вас просто завалить.

Во-первых, это явно не проблема разработчика, скажем честно.
Во-вторых, зачем создавать самому себе (и коллегам) проблему на ровном месте? Если пришёл 5xx — это почти всегда означает, что сервер не справился и почти всегда означает, что повторная попытка приведёт к тому же самому результату. Иключений так мало, что можно пренебречь и обрабатывать отдельно.

S>2. Со стороны клиента, достаточно брать паузу при ошибках. В реальной среде вы вряд ли получите DOS из-за проблем обратного канала: характерное время, за которое вы получаете таймаут — около 5 секунд (это оптимистично). Чаще делают таймауты в 30 секунд. "Долбя" сервер запросами раз в полминуты, вы никакого DOS не устроите.

Вообще не нужно, нужно сказать — ошибка, звоните в поддержку если чё и все дела. Ибо у вас падает сервер.

S>3. Самое главное: а какая альтернатива? Никакого способа сделать лучше в природе не существует. См. "проблема двух генералов".

Альтернатива не долбиться головой об стенку после того как поставил шишку.
Все будет Украина!
Re[20]: REST: прохой\хороший интерфейс
От: Sinclair Россия https://github.com/evilguest/
Дата: 13.02.20 16:33
Оценка:
Здравствуйте, Ватакуси, Вы писали:
В>Телепат в студии? Откуда известно что и кому неизвестно?
Потому что DDOS — это когда у нас есть "нормальные" клиенты, которые пытаются получить сервис, и есть распределённая сеть ботов, которые посылают запросы не для того, чтобы они были выполнены, а для того, чтобы не дать "нормальным" клиентам получить сервис.
Один клиент DDOS обеспечить не в состоянии, по определению DDOS.
Множество "нормальных" клиентов DDOS-атаку тоже не проводят; то, что часть запросов отпадает, означает просто недостаточность серверных мощностей.

S>>1. Со стороны сервера, вам в любом случае нужно думать о throttling. Потому что нет никакой гарантии, что клиенты ведут себя прилично, и не захотят вас просто завалить.

В>Во-первых, это явно не проблема разработчика, скажем честно.
Не очень понимаю это утверждение. Кто должен решать эту проблему, по-вашему?
В>Во-вторых, зачем создавать самому себе (и коллегам) проблему на ровном месте? Если пришёл 5xx — это почти всегда означает, что сервер не справился и почти всегда означает, что повторная попытка приведёт к тому же самому результату. Иключений так мало, что можно пренебречь и обрабатывать отдельно.

S>>2. Со стороны клиента, достаточно брать паузу при ошибках. В реальной среде вы вряд ли получите DOS из-за проблем обратного канала: характерное время, за которое вы получаете таймаут — около 5 секунд (это оптимистично). Чаще делают таймауты в 30 секунд. "Долбя" сервер запросами раз в полминуты, вы никакого DOS не устроите.

В>Вообще не нужно, нужно сказать — ошибка, звоните в поддержку если чё и все дела. Ибо у вас падает сервер.

S>>3. Самое главное: а какая альтернатива? Никакого способа сделать лучше в природе не существует. См. "проблема двух генералов".

В>Альтернатива не долбиться головой об стенку после того как поставил шишку.
Вот прямо даже не знаю, с чего начать.
Ок, начнём с конца.
1. Предположим, клиент позвонил в поддержку, поддержка пнула кого надо, проблема исправлена. Что делать дальше? Есть ли у вас уверенность (а если есть, то откуда) в том, что надо повторять (или не повторять) вызов?
Вы предлагаете обсуждать этот вопрос с поддержкой для каждого из 150000 вызовов, упавших, пока сервер "не справлялся"?
2. Предположим, надо повторить заказ. Как мы узнаем, когда это делать?
Будем ждать, чтобы поддержка отписала в тикет "всё норм, попробуйте ещё раз"? Не дороговат ли канал для передачи Retry-After?
3. Теперь попробуем понять, а что вообще могло пойти не так.
Я так понял, что по вашему опыту, 5хх означает в подавляющем большинстве случаев то, что сервак ложится под нагрузкой, и любые повторные попытки будут делать только хуже.
По моему опыту, частота причин для 5хх примерно такая:
А. проблемы с администрированием: кончилось место на диске, протух пароль для внешнего сервера, проэкспайрился сертификат.
Б. техобслуживание: мы просто перезагружаем сервак, и клиент это видит либо как таймаут, либо как 502 от прокси-сервера.
В. проблемы с тестированием: одна из веток кода бросает необработанное исключение, потому что до её проверки не дошли руки. То есть она должна отдавать либо 4хх (недостаточная валидация инпута стреляет ниже по стеку), либо 2хх (тупо бага в коде).
Ситуация, при которой у нас не хватает мощностей — большая редкость для нас. Как правило, и наши сервисы, и сторонние сервисы проектируются с запасом по нагрузке. Если бы мы имели ситуации с неконтролируемыми вспышками активности, то звонки в саппорт бы мы и так получили.
Во всех остальных случаях повторные попытки никак не влияют на ситуацию: скажем, скорость перезагрузки сервера не зависит от того, долбят ли сейчас в прокси периметра что-то нетерпеливые клиенты.

Если посмотреть на ситуацию шире, то опыт примерно такой: на то, что наш софт продолжает ретраить в тупиковых ситуациях, жалоб на моей памяти не было. Ну долбит и долбит — это никому ничего не стоит.
А вот на то, что он перестаёт ретраить, жалобы были. Потому что ситуация "у нас упало 10000 заказов в очереди из-за проблемы в сервисе ХХХ" стоит разных убытков в случае "мы позвонили им в саппорт, они починили, и всё поехало", и в случае "мы позвонили им в саппорт, они починили, и теперь нам нужно определить, какие из 13000 заказов в очереди застряли из-за этой проблемы, и сделать им ручной рестарт".
А ситуация "те заказы, которые мы пытались протолкнуть, упали фатально, их нужно отменять и заказывать по новой" вообще может стать поводом для эскалации на уровень Senior Vice President с раздачей дюлей по цепочке подчинения.
Потому, что денег стоят человеко-часы. В первом варианте мы имеем ущерб в 1 час, во втором — в 100, в третьем — в 5000.
И каждый час лишней задержки исполнения заказа, висящего в очереди из-за 5хх в стороннем сервисе, стоит нам примерно 10% churn. То есть шансы на то, что клиент дождётся ручной разблокировки очереди, стремительно падают.

Именно поэтому я — фанат клиентов, которые умеют сами делать повторные обращения, и сервисов, которые умеют в случае проблем дирижировать этими обращениями.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[17]: REST: прохой\хороший интерфейс
От: Sinclair Россия https://github.com/evilguest/
Дата: 13.02.20 16:52
Оценка:
Здравствуйте, Sharov, Вы писали:

S>Трабования имеют св-во менятся, зачастаю неожиданным и непредсказуемым образом.

1. Внезапность — это неосознанная неизбежность
Знаете, как говорят: "если вы ведёте машину, и на дороге происходит что-то неожиданное — значит, ваша квалификация как водителя недостаточна"
Это, конечно, преувеличение, но в целом слабые места дизайна можно предвидеть заранее. Например, длина URL в Get-запросах.
Вот у вас, как я понял, не очень много опыта в проектировании REST API, и тем не менее вас вопрос ограничения длины заинтересовал.
Это значит, что при прояснении требований вы этот вопрос зададите — заказчику, или себе. В каких-то случаях у вас будет гарантия успеха — потому что все нужные параметры имеют заведомо ограниченную длину.
В каких-то других случаях вы сможете предсказать, что достаточное количество реальных запросов уложится в ограничение. Например, поисковые запросы в Гугл теоретически могут превысить эти килобайты.
Тем не менее, гугл не постеснялся выставить свой поисковый API через GET.
Сочли, что желающие искать в интернете целые главы по их полному тексту обойдутся.

Вы можете столкнуться с задачей типа "скачать пачку книг (допустим, в .tar) по их ISBN". Реализация этой задачи через GET наложит ограничение на максимальное количество книг в батче.
Ну и что? Просто опишете это в документации (ну, или в теле 400 Bad Request) и всё.
Преимущества у такой реализации всё ещё перевешивают недостатки.
Только если значительное количество клиентов будут упираться в это ограничение, у вас будет повод усложнить протокол — скажем, сделать сущность "запрос на скачивание", который будет PUT-ом (или POST-ом) закидывать список ISBN, и потом уже отдельным GET закачивать данные по короткому URL.

Про RPC я и не говорю — сделать нормальную реализацию подобного сервиса через RPC близко к невозможному. То, что получится у 70% архитекторов, будет в разы хуже REST по наблюдаемым характеристикам, а то, что смогут сделать 30%, не одобрит менеджмент со словами "нафига козе баян, это как-то сложно и дорого".

S>В целом, Вы правы, так думать можно. Но, думается, когда Филдинг все это дизайнил речь шла о конретных, конечных ресурсах, типа стат. html страничек. Т.е. что-то сущ. и конечное.

Неважно, о чём он думал. Важно то, что он придумал в итоге.
S>Все можно положить на rest, но не всегда нужно.
S>Помню где-то читал, и недавно, но найти не могу.
Я думаю, что вы неверно поняли.
Вот, к примеру, гугл. Вы же не думаете, что существует такой ресурс, как "список страниц с упоминанием термина 'финтифлюшка' и его аналогов", так?
И никого-никого в мире не смущает то, что по адресу https://www.google.com/search расположено бесконечное количество страниц.
Так почему же должно смущать наличие бесконечной таблицы умножения по адресам типа https://multiplication.com/53423423/times/123121 ?
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re: REST: прохой\хороший интерфейс
От: alexanderfedin США http://alexander-fedin.pixels.com/
Дата: 13.02.20 21:18
Оценка:
Здравствуйте, a.v.v, Вы писали:
AVV>Во многих вакансиях появилось требование звучащее как — уметь проектировать хороший rest интерфейс
AVV>вот и задумался а что такое этот хороший интерфейс, у самого есть конечно мысли но какие то они не очень убедительные
AVV>вот хотел бы послушать коллективное бессознательное
Есть два подхода к дизайну REST интерфейсов:
  1. Строго следовать парадигме CRUD (POST/GET/PUT/DELETE) и делать urls идентифицирующие ресурсы
  2. Понимать performance impacts от принятых решений и кое-где отходить от CRUD, поскольку batch операции нормально/правильно задизайнить можно только для GET.

AVV>заранее благодарю

Не благодари.
Respectfully,
Alexander Fedin.
Re[18]: REST: прохой\хороший интерфейс
От: Pavel Dvorkin Россия  
Дата: 14.02.20 03:30
Оценка:
Здравствуйте, Sinclair, Вы писали:

PD>>Если бы тут никакого ревизора не было, а просто надо было бы вновь приехавашего добавить в книгу проезжающих — POST классический.

S>Нет. POST — это самый плохой из всех HTTP глаголов, т.к. он предоставляет минимум гарантий. Чтобы его использовать, нужны веские причины.

Верно! Истину глаголешь.

POST прячем в карман. Что остается ?

PUT — методы, которые вносят какие-то изменения
GET — методы, которые не вносят никакие изменения
DELETE — особый случай : методы, которые вносят изменения, но только типа удаления.

Теперь заменяем странный способ передачи параметров в трех местах (header, line, body), вызывающий бесконечные дискуссии о том, где какой параметр надо передавать, на обычный вызов функции с параметрами

И получаем RPC.




PD>>Report addPerson(Person);

PD>>Можно поинтересоваться, какие механизмы контроля есть в обычном LPC ? Например, при добавлении картинки на холст ?
S>В обычном LPC эти механизмы и не нужны — там не бывает ситуации типа "мы не знаем, удалось ли нам сделать вызов, или нет".
Даже если между caller и callee возникла коммуникационная проблема (переполнился стек, ну или адрес вызова оказался булшитом), то мы получаем вполне внятное исключение. В RPC нет такой роскоши.

Почему ты так решил ? Если клиент thrift пытается сделать вызов, а сеть вообще упала или урл/порт не верен, он получит вполне внятное исключение — тот же самый TTransportException, внутри которого будет IOException с обычным объяснением причины ?

PD>>Нет, не устраивает, ибо гуси с гусенками не будут удалены, а Держиморда будет по-прежнему махать кулаками.

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

Мухлюешь ты. Или же плохо знаешь "Ревизор".
Зачем клиент послал ревизора — а бог его знает, в пьесе об этом ничего. Есть лишь отвергнутая гипотеза о поиске измены.
Послал и послал. Может, он от него ждет Report.
А вот в ходе этого действия надо, как оказалось, удалить гусей с гусенками.
Важное лицо, отправившее ревизора, я полагаю, о гусях вовсе не думало, и ревизор отправлен не для того, чтобы их на кухню отправить.
А вот надо, как выяснилось, именно это сделать — как следствие посылки ревизора.


S>Ты покажи мне десктопное приложение, которое работает с разделяемым состоянием — 90 против 1, что оно ходит на сервер по http.


Да бога ради, любой клиент SQL сервера. Ну не ходит MySQL Workbench или SQLYog на MySQL сервер по HTTP.
А Skype по HTTP ходит ?
А Windows клиенты для Active Directory ? Между прочим, домен может быть очень и очень распределенным, а то и целый лес доменов


PD>>https://www.javatips.net/api/org.apache.thrift.transport.ttransportexception

S>Не верю. Чудес не бывает. Никакими ексепшнами ты проблему двух генералов не решишь.

Что за проблема двух генералов ? Тех, которых мужик кормил у Салтыкова — Щедрина ? Если да — при чем они тут ?

PD>>Тоже TTransportException, если задать таймаут.

S>Ну, и? Как мне понять, где произошёл transportException — на этапе передачи запроса, или на этапе передачи ответа?

Смотреть, что там внутри, как всегда.

S>Вот я делаю placeOrder() — как сделать так, чтобы гарантированно разместить не более 1 заказа, при условии ненадёжности сети?


Вот я делаю добавление на холст новой картинки — как мне гарантированно дважды ее не разместить ? Проверить результат размещения, и если он неудачен, то размещать заново
Вот я делаю INSERT в таблицу БД — как мне гарантированно дважды ее не добавить ? Проверить результат добавления, и если он неудачен, то добавлять заново. Кстати, сеть тут почти наверняка задействована.

Ты почему-то решил, что наличие сети делает ситуацию совершенно особой. А это всего лишь компонент, конечно, гораздо менее надежный, чем другие. Вероятность того, что при записи в файл будет IOException, на порядки меньше, чем вероятность того, что при работе с thrift будет TTransportException. Но только идиот не будет предпринимать меры в отношении возможного IOException при работе с файлом или какого-то исключения от БД

PD>>Вот этот тезис я принимаю. Но этот факт не отменяет того, что для реализации этого стандарта был выбран инструмент, изначально заточенный для других, более простых задач, в результате чего его допиливали и натягивали на эти задачи. Вместо того, чтобы предложить иной протокол, более адекватный для современных приложений. А как его реализовать — вопрос десятый. Можно и поверх RPC, можно и просто поверх TCP/IP. RPC-то тоже через TCP/IP работает.


S>Например, инкрементальности передачи в RPC нету — примитив же, просто "байты по сети". Он лишь чуть лучше, чем голый TCP-стрим. А в HTTP инкрементальность заложена в сам протокол. При этом сервер не обязан её поддерживать — можно запустить proof of concept без неё, и все клиенты и прокси прекрасно будут с твоим сервером работать. Потом прикручиваешь инкрементальность — и все существующие клиенты продолжают работать. А те из них, которые умеют инкрементальность, получают преимущество в тот же момент.

S>Или компрессию.
S>Причём у тебя один и тот же протокол могут отдавать три сервера — в одном есть инкрементальная передача, в другом компрессия, в третьем и то и другое. И клиенты будут прекрасно работать со всеми тремя.
S>В RPC протоколе эта задача потребует настолько адских приседаний, что шансов получить под них бюджет очень мало.

Нету, нету. Согласен. RPC — голый вызов функций. Обычный вызов функций, только под спудом маршаллинг на другую машину. Естественно, ждать от него инкрементальности, кеширования и т.д. можно с тем же успехом, сколько от простого вызова функций в пределах десктопного приложения. Сделаете сами — будет, не сделаете — не будет.
Но я же не об этом. Я о том, что протокол, изначально заточенный под совсем другие задачи, натянули на современные клиент-серверные приложения. А нужно было что-то более логичное.
With best regards
Pavel Dvorkin
Re[19]: REST: прохой\хороший интерфейс
От: Sinclair Россия https://github.com/evilguest/
Дата: 14.02.20 04:17
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:


PD>PUT — методы, которые вносят какие-то изменения

PD>GET — методы, которые не вносят никакие изменения
PD>DELETE — особый случай : методы, которые вносят изменения, но только типа удаления.

PD>Теперь заменяем странный способ передачи параметров в трех местах (header, line, body), вызывающий бесконечные дискуссии о том, где какой параметр надо передавать, на обычный вызов функции с параметрами


PD>И получаем RPC.

Не совсем так. Просто заменив обращения к HTTP глаголам на вызовы RPC, мы теряем информацию о том, какие методы safe, а какие — idempotent. Как ты поймёшь, можно ли кэшировать результат вызова RPC-метода?

Кроме того, сигнатуры RPC методов просто взорвутся. Ты себе представляешь, сколько метаданных там ездит в хидерах?
Попробуй для начала переписать простейший GET /people/{personId} в RPC.
Не забудь, что нужно уметь:
1. Делать перенаправление — когда сервер редиректит клиента на другой сервер,
2. Принимать таймстамп кэша и хеш от данных, и возвращать аналог Not modified
3. Поддерживать инкрементальную загрузку — если в прошлый раз доехала только половина данных, то мы должны уметь запросить вторую половину, не запрашивая всю передачу
4. Поддерживать сжатие результата
5. Поддерживать локализацию — клиент передаёт список известных ему культур в порядке убывания предпочтений, сервер выбирает наиболее предпочтительную из поддерживаемых им культур

Жду сигнатуру RPC метода, который это всё умеет.

PD>Почему ты так решил ? Если клиент thrift пытается сделать вызов, а сеть вообще упала или урл/порт не верен, он получит вполне внятное исключение — тот же самый TTransportException, внутри которого будет IOException с обычным объяснением причины ?

Павел, при чём тут причина? Может ли это исключение мне сказать, деньги-то списались или нет? Как мне сделать так, чтобы

PD>>>Нет, не устраивает, ибо гуси с гусенками не будут удалены, а Держиморда будет по-прежнему махать кулаками.

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

PD>Мухлюешь ты. Или же плохо знаешь "Ревизор".

PD>Зачем клиент послал ревизора — а бог его знает, в пьесе об этом ничего. Есть лишь отвергнутая гипотеза о поиске измены.
PD>Послал и послал. Может, он от него ждет Report.
PD>А вот в ходе этого действия надо, как оказалось, удалить гусей с гусенками.
PD>Важное лицо, отправившее ревизора, я полагаю, о гусях вовсе не думало, и ревизор отправлен не для того, чтобы их на кухню отправить.
PD>А вот надо, как выяснилось, именно это сделать — как следствие посылки ревизора.
"Надо именно это" — это внутреннее состояние сервера. Протокол взаимодействия, контракт сервера, никаких гусёнков и держиморд не содержит. В твоей RPC реализации никаких Report клиент не ожидает, и ты считаешь такой протокол корректным. Ну, считаешь и считаешь — твоё право. Но тогда этому протоколу удовлетворяет и dev/null.

S>>Ты покажи мне десктопное приложение, которое работает с разделяемым состоянием — 90 против 1, что оно ходит на сервер по http.


PD>Да бога ради, любой клиент SQL сервера. Ну не ходит MySQL Workbench или SQLYog на MySQL сервер по HTTP.



PD>Что за проблема двух генералов ? Тех, которых мужик кормил у Салтыкова — Щедрина ? Если да — при чем они тут ?

https://ru.wikipedia.org/wiki/%D0%97%D0%B0%D0%B4%D0%B0%D1%87%D0%B0_%D0%B4%D0%B2%D1%83%D1%85_%D0%B3%D0%B5%D0%BD%D0%B5%D1%80%D0%B0%D0%BB%D0%BE%D0%B2

PD>>>Тоже TTransportException, если задать таймаут.

S>>Ну, и? Как мне понять, где произошёл transportException — на этапе передачи запроса, или на этапе передачи ответа?

PD>Смотреть, что там внутри, как всегда.

Внутри чего?

PD>Вот я делаю INSERT в таблицу БД — как мне гарантированно дважды ее не добавить ? Проверить результат добавления, и если он неудачен, то добавлять заново. Кстати, сеть тут почти наверняка задействована.

Ну вот да, Павел. Поэтому в здравом уме никто напрямую в таблицу insert через океан и не делает. А когда делают репликацию, то по факту приходят именно к representational state transfer, хоть не обязательно через HTTP.
Приведи пример кода, который решает эту задачу на SQL. Полезное упражнение. А потом мы посмотрим, как так получается, что REST-метод, который в некотором смысле всего лишь надстройка над INSERT INTO, гарантированно не добавляет запись дважды.


PD>Ты почему-то решил, что наличие сети делает ситуацию совершенно особой. А это всего лишь компонент, конечно, гораздо менее надежный, чем другие. Вероятность того, что при записи в файл будет IOException, на порядки меньше, чем вероятность того, что при работе с thrift будет TTransportException. Но только идиот не будет предпринимать меры в отношении возможного IOException при работе с файлом или какого-то исключения от БД

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

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

Я не возражаю против более логичного. Но вот RPC — он заведомо менее логичный, чем REST.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[20]: REST: прохой\хороший интерфейс
От: Pavel Dvorkin Россия  
Дата: 14.02.20 05:07
Оценка:
Здравствуйте, Sinclair, Вы писали:

Ладно, пора заканчивать.

S>Кроме того, сигнатуры RPC методов просто взорвутся. Ты себе представляешь, сколько метаданных там ездит в хидерах?

S>Попробуй для начала переписать простейший GET /people/{personId} в RPC.
S>Не забудь, что нужно уметь:
S>1. Делать перенаправление — когда сервер редиректит клиента на другой сервер,
S>2. Принимать таймстамп кэша и хеш от данных, и возвращать аналог Not modified
S>3. Поддерживать инкрементальную загрузку — если в прошлый раз доехала только половина данных, то мы должны уметь запросить вторую половину, не запрашивая всю передачу
S>4. Поддерживать сжатие результата
S>5. Поддерживать локализацию — клиент передаёт список известных ему культур в порядке убывания предпочтений, сервер выбирает наиболее предпочтительную из поддерживаемых им культур

Ты упорно мыслишь в психологии HTTP.

Какое такое перенаправление ? В HTTP — понятно, а в вызове процедуры на сервере о чем вообще речь может идти ? Я обращаюсь к серверу, вызываю его метод. Нет тут URL (точнее, он один был при соединении) и нечего перенаправлять. Если нужно, пусть сервер и перенаправляет куда хочет — тем же способом. Клиента это не интересует.
Остальное аналогично. Пусть сервер там и разбирается, что modified, а что нет.
Какие метаданные и в каких хидерах ? Нет тут хидеров и нет метаданных. Есть Person, которую надо с сервера получить. Здесь столько же метаданных и хидеров, сколько в SELECT * FROM persons WHERE
Сжатие — ну если нужно, пусть метод делает zip и возвращает byte[] или ByteBuffer. thrift, кстати, ByteBuffer очень любит и все двоичные данные именно в виде его и передает
With best regards
Pavel Dvorkin
Re[22]: REST: прохой\хороший интерфейс
От: Pavel Dvorkin Россия  
Дата: 14.02.20 07:14
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>Здравствуйте, Pavel Dvorkin, Вы писали:


PD>>Ладно, пора заканчивать.

S>Ну естественно. Как дело доходит до конкретики, фанаты RPC разбегаются из треда.

Ладно, отвечу.

Все твои возражения можно изложить очень коротко

Если через RPC передавать "голые" объекты — будут проблемы. Нужен протокол верхнего уровня.
Такого протокола в RPC действительно нет. Там передается и возвращается поток байтов.
Что никак не мешает его иметь.

Вот давай гипотетический (подчеркиваю, гипотетический) вариант рассмотрим

RPC. Отсылается ByteBuffer. Возвращается ByteBuffer.

В исходящем ByteBuffer упаковано все , что сейчас посылается по HTTP. Все, без исключения
В возвращаемом — аналогично.

Вот тебе HTTP на основе RPC. Шли то же, получишь то же. Только без HTTP, а в ByteBuffer.

А теперь вместо HTTP делаем что-то более напоминающее год 2020, а не год 1980. Не раскидываем там параметры в трех местах. Не возвращаем коды в виде , напоминающем С времен K&R. Не пакуем параметры через амперсенд, что мне напоминает времена моей молодости. И т.д.

И все, что ты хочешь, будет, но только в виде, более подходящем для 2020 года

И модифицировать этот протокол будет намного легче. Нужен аналог PUT — будет там PUT. Нужен аналог POST — будет там POST. Нужен некий CONVERT — будет там и CONVERT.

Вот и все. Именно нечто подобное я в своем thrift-приложении и делал.

И на этом, извини, уж точно все. Не могу я эту дискуссию вести до второго пришествия.
With best regards
Pavel Dvorkin
Re[23]: REST: прохой\хороший интерфейс
От: Sinclair Россия https://github.com/evilguest/
Дата: 14.02.20 07:52
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

PD>Все твои возражения можно изложить очень коротко

PD>Если через RPC передавать "голые" объекты — будут проблемы. Нужен протокол верхнего уровня.
PD>Такого протокола в RPC действительно нет. Там передается и возвращается поток байтов.
PD>Что никак не мешает его иметь.
PD>В исходящем ByteBuffer упаковано все , что сейчас посылается по HTTP. Все, без исключения
PD>В возвращаемом — аналогично.
Хуже того. Такой протокол уже есть. Называется HTTP. У него внутри уже упаковано всё, что посылается по HTTP.
PD>А теперь вместо HTTP делаем что-то более напоминающее год 2020, а не год 1980. Не раскидываем там параметры в трех местах. Не возвращаем коды в виде , напоминающем С времен K&R. Не пакуем параметры через амперсенд, что мне напоминает времена моей молодости. И т.д.
PD>И все, что ты хочешь, будет, но только в виде, более подходящем для 2020 года
Ну да. И ждём ещё 30 лет, пока для твоего нового протокола появятся nginx и CDN-провайдеры. Делов-то.
PD>И модифицировать этот протокол будет намного легче. Нужен аналог PUT — будет там PUT. Нужен аналог POST — будет там POST. Нужен некий CONVERT — будет там и CONVERT.
Нее, Павел. Давай пример. Мы говорим про конкретный, уже стандартизованный протокол. А ты в ответ "да я могу гипотетически то, гипотетически сё...".
Сколько будет стоить эта твоя гипотетика? Ну, без стоимости разработки nginx, а просто сам протокол?
Сможешь ли ты её хотя бы спроектировать корректно? А то вон ты уже нацелился изобретать глагол CONVERT, явно не задумываясь о том, будет ли он safe, idempotent, или нет.
Не понимая, как это всё будет взаимодействовать со сторонним софтом вроде тех же проксей, лоад-балансеров, и delivery networks.

Причём заметь — ты всё это время будешь писать только "основу". Собственно, заворачивал HTTP в RPC. Когда ты закончишь, настанет время писать прикладной протокол поверх этого "HTTPoverRPC".
То есть для той работы, которую собственно ведёт разработчик REST каждый раз, как ему нужно изобрести API для конкретного приложения.
Внезапно оказывается, что само по себе использование HTTP никаких гарантий не даёт — вон, идиоты придумали SOAP. Страшно подумать, сколько было денег закопано в эту яму. Он-то ведь тоже вполне себе HTTP, только без преимуществ HTTP.
PD>Вот и все. Именно нечто подобное я в своем thrift-приложении и делал.
А теперь главный вопрос — а выигрыш-то в чём? Ну сделал ты свой протокол для реализации REST. Получил все те же преимущества, что и в нём.
Единственная разница — в этом протоколе ты, возможно, будешь разбираться. А то про HTTP у тебя какие-то мифологизированные представления, вроде "параметров через амперсанд".
Мы, кстати, это уже десять лет назад обсуждали — я тебе ещё тогда указывал на твои заблуждения. Увы, увы. Почему-то изобретение своего протокола по-прежнему представляется более простым делом, нежели изучение существующего.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[25]: REST: прохой\хороший интерфейс
От: Sinclair Россия https://github.com/evilguest/
Дата: 14.02.20 09:11
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>Я говорю о том, как это нужно было бы сделать "как следует".
Пока что в обсуждении не прозвучало ни одной идеи, "как следует" делать прикладные протоколы. Ну, кроме заблуждений и недопонимания того, какие реальные проблемы заслуживают решения.

Ну вот, авторам исходного RPC казалось, что самое сложное — это упаковать параметры вызова и распаковать результат. Поэтому они уделили большое внимание маршалингу. "Оо, смотрите, вам не нужно беспокоится о переводе байтов в сетевой порядок и обратно, и не надо определять границы пакетов. Как же ж это круто!". Ну, а ошибки — чо там, бросим исключение да и всё.

Авторам SOAP казалось, что в RPC недостаточно ада. А вдруг злоумышленник исказит наш запрос или ответ на него! Дааа, давайте навернём свой собственный адски сложный и расширяемый стандарт цифровой подписи.
Главное — чтобы заказчик понимал, что вещь сложная, стоить дёшево не может.
Дальше там что у нас? Проблемы с консистентностью? Дааа, давайте навернём свой стандарт двухфазного коммита. Сделаем его опциональным. Больше тегов, больше расширяемости, больше риска взаимной несовместимости.
Зато выглядит копец как солидно — откроешь пакет вайршарком, а там ууууу! Неймспейсы, неймспейсы, хидер, боди, всё такое. Тулчейн весом полтора гигабайта, WSDL, генератор WSDL по коду, генератор кода по WSDL.

Энтерпрайзненько, чо.

REST на этом фоне выглядит, конечно, несолидно. Ну что это такое — взял да запросил респонс! Прямо вот так вот, GET — и всё! Любой школьник может написать клиента к публичному API прямо на коленке в notepad.exe. А проверить этот АПИ можно вообще гражданским браузером. Ну куда это годится! Нет, это не для кровавого энтерпрайза.

К счастью, здравый смысл победил. Ну, а WindowsXP/7/10 продолжают подьезжать — вон, Гугл своё видение прикладных протоколов проталкивает, поверх HTTP/2.
Посмотрим, к чему придут. Пока что у меня нет ощущения, что они там дуют в нужную сторону; ну да посмотрим.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[16]: REST: прохой\хороший интерфейс
От: Sharov Россия  
Дата: 14.02.20 11:06
Оценка:
Здравствуйте, Sinclair, Вы писали:


S>Можно ссылку на эти рекомендации? Может, я что-то упустил.


https://stackoverflow.com/a/53853161/241446 -- тут говорят, что это не очень rest compatible, но ни этот источник я имел в виду.

Use nouns to represent resources

RESTful URI should refer to a resource that is a thing (noun) instead of referring to an action (verb) because nouns have properties which verbs do not have – similar to resources have attributes. Some examples of a resource are:


Правди далее допускается контроллер:

A controller resource models a procedural concept. Controller resources are like executable functions, with parameters and return values; inputs and outputs.

Use “verb” to denote controller archetype.

http://api.example.com/cart-management/users/{id}/cart/checkout
http://api.example.com/song-management/users/{id}/playlist/play

https://restfulapi.net/resource-naming/

Т.е. calculate?expression=((1800*999)-677)/65866556 все же неправильно, не rest compatible.
Кодом людям нужно помогать!
Re[17]: REST: прохой\хороший интерфейс
От: Sinclair Россия https://github.com/evilguest/
Дата: 14.02.20 12:29
Оценка:
Здравствуйте, Sharov, Вы писали:

S>Т.е. calculate?expression=((1800*999)-677)/65866556 все же неправильно, не rest compatible.

Да без проблем.
GET /((1800*999)-677)/65866556/value

Так лучше?
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[18]: REST: прохой\хороший интерфейс
От: Sharov Россия  
Дата: 14.02.20 12:52
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>Здравствуйте, Sharov, Вы писали:


S>>Т.е. calculate?expression=((1800*999)-677)/65866556 все же неправильно, не rest compatible.

S>Да без проблем.
S>
S>GET /((1800*999)-677)/65866556/value
S>

S>Так лучше?

GET expression/"((1800*999)-677)/65866556"/calculate
Кодом людям нужно помогать!
Re[19]: REST: прохой\хороший интерфейс
От: Sinclair Россия https://github.com/evilguest/
Дата: 14.02.20 12:56
Оценка:
Здравствуйте, Sharov, Вы писали:

S>GET expression/"((1800*999)-677)/65866556"/calculate

Ну нет, зачем нам calculate? Вы совершенно правы — нас интересует value выражения. А посчитано оно или взято из диска — совершенно умозрительный вопрос.
Вот, например, таблицы Брадиса же можно просто отсканировать и распознать — будет у нас GET /tables/sin/valueAt/0/
А можно там внутри быстренько посчитать сумму ряда и вернуть результат
Заодно получим возможность передавать в аргументы синуса любое число, а не только от -Pi до Pi, как у Брадиса.
Или, например, берём
GET /5413513543123543543864524354351354/primeFactors
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[26]: REST: прохой\хороший интерфейс
От: Serginio1 СССР https://habrahabr.ru/users/serginio1/topics/
Дата: 14.02.20 13:03
Оценка:
Здравствуйте, Sinclair, Вы писали:


S>Дальше там что у нас? Проблемы с консистентностью? Дааа, давайте навернём свой стандарт двухфазного коммита. Сделаем его опциональным. Больше тегов, больше расширяемости, больше риска взаимной несовместимости.

S>Зато выглядит копец как солидно — откроешь пакет вайршарком, а там ууууу! Неймспейсы, неймспейсы, хидер, боди, всё такое. Тулчейн весом полтора гигабайта, WSDL, генератор WSDL по коду, генератор кода по WSDL.

Ну есть Swagger говорят вполне приличный. Есть еще и Refit https://github.com/reactiveui/refit
Ну и ODATA и Linq https://docs.microsoft.com/ru-ru/dotnet/framework/data/wcf/linq-considerations-wcf-data-services
и солнце б утром не вставало, когда бы не было меня
Отредактировано 14.02.2020 14:25 Serginio1 . Предыдущая версия .
Re[26]: REST: прохой\хороший интерфейс
От: swimmers  
Дата: 17.02.20 08:51
Оценка:
Здравствуйте, Sinclair, Вы писали:
...

Антон, как по твоему надо поступать в следующей ситуации:
Есть некоторая ИС, в которой несколько сотен справочников.
Есть несколько (веб)приложений, которым для работы нужны в т.ч. эти справочники.
При этом разным приложениям надо читать разный состав атрибутов справочников, условно, кому-то достаточно пары ключ-значение, кому-то нужны все атрибуты.
Плюс, некоторые записи в некоторых справочниках должны ограничиваться по правам доступа, т.е. конкретному клиенту могут возвращаться 10 записей из 100.

Как, на твой взгляд нам реорганизовать Рабкрин наиболее эффективно спроектировать АПИ, чтобы воспользоваться преимуществами REST(HTTP)?
Re[27]: REST: прохой\хороший интерфейс
От: Sinclair Россия https://github.com/evilguest/
Дата: 21.02.20 06:58
Оценка:
Здравствуйте, swimmers, Вы писали:

S>Здравствуйте, Sinclair, Вы писали:

S>...

S>Антон, как по твоему надо поступать в следующей ситуации:

S>Есть некоторая ИС, в которой несколько сотен справочников.
S>Есть несколько (веб)приложений, которым для работы нужны в т.ч. эти справочники.
S>При этом разным приложениям надо читать разный состав атрибутов справочников, условно, кому-то достаточно пары ключ-значение, кому-то нужны все атрибуты.
S>Плюс, некоторые записи в некоторых справочниках должны ограничиваться по правам доступа, т.е. конкретному клиенту могут возвращаться 10 записей из 100.

S>Как, на твой взгляд нам реорганизовать Рабкрин наиболее эффективно спроектировать АПИ, чтобы воспользоваться преимуществами REST(HTTP)?

Ну, как обычно — берём, выставляем каждый справочник как ресурс, права доступа накладываем на стороне сервера, cache-control делаем private, чтобы случайно не перемешать ответы.
Если вариантов набора атрибутов в каждом справочнике мало, то можно просто выставить их как варианты справочника (например, передав в URL выбор проекции, типа ?attr=all илии ?attr=compact).
Если их слишком много — то даём клиенту выбрать нужную проекцию.
Проще всего — воспользоваться готовым протоколом и готовой реализацией, например OData.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[7]: REST: прохой\хороший интерфейс
От: Serginio1 СССР https://habrahabr.ru/users/serginio1/topics/
Дата: 25.04.20 09:32
Оценка:
Здравствуйте, Serginio1, Вы писали:

S>Здравствуйте, Sinclair, Вы писали:


S>>Здравствуйте, Serginio1, Вы писали:


S>>> Что скажешь по gRPC

S>>>https://habr.com/ru/company/infopulse/blog/265805/
S>>Надо читать. Выглядит подозрительно.

S>Вот нашел еще статью на Хабре

S>https://habr.com/ru/company/yandex/blog/484068/

Добавлю еще одну статью про gRPC
https://habr.com/ru/post/488102/

Посмотрел https://docs.microsoft.com/ru-ru/aspnet/core/grpc/client?view=aspnetcore-3.1
Там и потоковая передача данных предусмотрена,

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


https://habr.com/ru/company/microsoft/blog/487548/?mobile=no

Новые возможности с gRPC-Web

Вызов приложений ASP.NET Core gRPC из браузера — API браузера не могут вызывать gRPC HTTP/2. gRPC-Web предлагает совместимую альтернативу.
JavaScript SPA
Приложения .NET Blazor Web Assembly
Размещать приложения ASP.NET Core gRPC в IIS и службе приложений Azure. Некоторые серверы, такие как IIS и служба приложений Azure, в настоящее время не могут размещать службы gRPC. В то время как над этим активно работают, gRPC-Web предлагает интересную альтернативу, которая сегодня работает в любой среде.
Вызов gRPC с платформ, отличных от .NET Core. Некоторые платформы .NET HttpClient не поддерживают HTTP/2. gRPC-Web может использоваться для вызова сервисов gRPC на этих платформах (например, Blazor WebAssembly, Xamarin).

Обратите внимание, что gRPC-Web требует небольших затрат на производительность, и две функции gRPC больше не поддерживаются: клиентская потоковая передача и двусторонняя потоковая передача. (потоковая передача на сервер все еще поддерживается!)

и солнце б утром не вставало, когда бы не было меня
Отредактировано 25.04.2020 19:50 Serginio1 . Предыдущая версия . Еще …
Отредактировано 25.04.2020 10:37 Serginio1 . Предыдущая версия .
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.