Здравствуйте, Sinclair, Вы писали:
S>Что именно вызывает затруднения?
Хм... Проблема в сбоях во время вызова weather — сервер запрос отработал, а клиент ответ не получил.
Пользователь будет повторять свой запрос и ему придется платить заново.
Здравствуйте, Буравчик, Вы писали: Б>Хм... Проблема в сбоях во время вызова weather — сервер запрос отработал, а клиент ответ не получил. Б>Пользователь будет повторять свой запрос и ему придется платить заново.
Да, GET подразумевает safe-семантику, т.е. изменением состояния сервера можно пренебречь.
При проектировании сервиса придётся принимать во внимание конкурирующие соображения: GET удобен с точки зрения сценария использования и возможностей кэширования.
В общем, если нам страшно потерять деньги (или выдать лишний ответ), то придётся по-честному выставлять управляемое состояние — то есть будет история "запросов погоды", будет правило "не больше 10 за 31 день" или ещё как-то, будут PUT, будут последующие GET.
Если же суперточность биллинга не принципиальна, и лимиты там не 10 в месяц, а 1000 в день, то работаем одним из следующих способов:
1. Пост-ограничение. Клиент, который шарашит нас большим количеством запросов, получает счёт за превышение лимита, или ему временно усиливают throttling.
2. Уточнение подсчётов — обучаемся отличать повторы "одного и того же" запроса от "новых" запросов, за "одинаковые" лимит не трогаем.
Встречный вопрос — а что нам предлагает RPC?
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, Sinclair, Вы писали:
S>2. Уточнение подсчётов — обучаемся отличать повторы "одного и того же" запроса от "новых" запросов, за "одинаковые" лимит не трогаем.
Здравствуйте, TG, Вы писали: TG>И тут уже requestId нужен, да?
Он одновременно не нужен и недостаточен. Мы же не хотим, чтобы хитрый клиент просто использовал 100 раз в месяц 1 RequestID
Так что без деталей я спроектировать API не могу.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, samius, Вы писали:
S>>>Влезу. Ну, например, калькулятор, который на удаленной машине чего-то считает. rpc прямолинеен, а вот с rest придется попотеть. Вообще, как я понимаю, rest нужен, когда мы имеем дело
... S>То есть, по-крайней мере название REST — это о том, как клиент хранит состояние сессии. Но, конечно, REST не ограничивается одной лишь этой идеей, в списке идей источников присутствует Remote Session.
Не совсем понятно к чему ты это говоришь. Какое состояние сессии в рассматриваемом примере калькулятора? Ведь тут не нужно никаких сессий, тривиальный запрос-ответ, никакого состояния репрезентить не надо.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Здравствуйте, ·, Вы писали:
·>Здравствуйте, samius, Вы писали:
S>>>>Влезу. Ну, например, калькулятор, который на удаленной машине чего-то считает. rpc прямолинеен, а вот с rest придется попотеть. Вообще, как я понимаю, rest нужен, когда мы имеем дело ·>... S>>То есть, по-крайней мере название REST — это о том, как клиент хранит состояние сессии. Но, конечно, REST не ограничивается одной лишь этой идеей, в списке идей источников присутствует Remote Session. ·>Не совсем понятно к чему ты это говоришь. Какое состояние сессии в рассматриваемом примере калькулятора? Ведь тут не нужно никаких сессий, тривиальный запрос-ответ, никакого состояния репрезентить не надо.
Я не о сессиях. Я о том, что именно за состояние фигурирует в названии REST. В духе того, что я процитировал из работы Филдинга, REST калькулятор вовсе не stateless. Когда мы говорим о состоянии в REST, то это не состояние, которое вынужден хранить сервер. Это состояние приложения в терминах машины состояний, по которым водят пользователя. Например:
Состояние редактирования выражения <=> состояние просмотра результата.
Здравствуйте, ·, Вы писали:
·>Здравствуйте, Sharov, Вы писали:
S>>·>Калькулятор это stateless — скучно и тривиально, решается одинаково просто практически на чём угодно левой пяткой во сне. А REST это всё-таки Representational state transfer. S>>Нам не нужен state, я же написал об этом. Нам нужны выч. ресурсы -- закинул задачу и пошел себе дальше. ·>Т.е. код примерно такой: ·>
Здравствуйте, Sinclair, Вы писали:
S>Здравствуйте, Sharov, Вы писали:
S>>Влезу. Ну, например, калькулятор, который на удаленной машине чего-то считает. rpc прямолинеен, а вот с rest придется попотеть. S>Даже напрячься не успеем. 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 нужен тогда, когда мы работаем с разделяемым состоянием.
А что такое разделяемое состояние -- подмножество всех состояний, которое хранится у данного клиента или что?
Именно с этого места и начинается 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 сек — что вы выберете? А что выберет ваш конкурент?
Здравствуйте, Sinclair, Вы писали:
S>Здравствуйте, Sharov, Вы писали: S>>Нам не нужен state, я же написал об этом. Нам нужны выч. ресурсы -- закинул задачу и пошел себе дальше. S>Вот прямо отличный пример. "Пошёл себе дальше" подразумевает, наверное, возможность как-то потом забрать результат, так? S>Значит, у нас появляется сущность "задача", и её состояние: "в очереди", "в процессе выполнения", "выполнена", "сбой выполнения". Это состояние нужно синхронизовывать между клиентом и сервером. S>Всё, REST начинает выигрывать у RPC ещё до начала забега — как раз потому, что он позволяет внятно описать CRUD над множеством задач. Ваши первые две-три реализации RPC будут страдать от детских болезней вроде "нечаянно поставил одну и ту же задачу в очередь дважды" или "задачу поставил — результат потерял".
Нет никакогов выигрыша. У нас запрос-ответ. Есть состояние на короткий интервал времени, причем от силы один глагол от всего rest(crud). Т.е. rpc не то что не позволяет crud, а он тут особо не нужен.
Вместо и взять и посчитать, мы разводим философию в стиле апорий Зенона. А результат можно забрать и polling'ом и по дуплексу(callback).
Здравствуйте, 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
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 пока не видать, да, скорее всего, увы, и не будет.
Здравствуйте, 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>А что такое разделяемое состояние -- подмножество всех состояний, которое хранится у данного клиента или что?
Это такое состояние, работа над которым ведётся совместно. Например, данный форум ценен именно тем, что наполнение форумов делается большим количеством участников. И у них есть согласованное представление о том, как устроены дискуссии — кто, когда, что, и на что отвечает.
Если бы мы отключили от форума всех участников, кроме вас, то вы могли бы скопировать его состояние (реплику базы) к себе, и править её локально любым удобным для вас образом. Соображения всяких идемпотентностей и кэширования были бы нерелевантны, т.к. был бы устранён ненадёжный и медленный канал между вами и состоянием системы.
Случай с "сервисом вычислений", когда вроде бы других пользователей, вмешивающихся в очередь заданий нету, тоже подходит под разделяемое состояние — на этот раз есть "пользователь", который ставит задачи и получает результаты, и "агент" — автомат, который решает вычислительные задачи и предоставляет их результаты.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, Sinclair, Вы писали:
S>Встречный вопрос — а что нам предлагает RPC?
Передачу ключей идемпотентности, как и REST. И нужно явно позаботиться об этом, как и в REST.
Интересно, что при проектировании приложения ты используешь анемик (ФП-стиль), но при проектировании API действуешь с точность до наоборот.
Рассматривая соседнюю тему о расчете надбавки, вероятно, в API появидсяся бы ресурс "рассчитать надбавку" (ок, просто "надбавка").
Но это и есть RPC-стиль, о котором я говорил выше. Работа от операций, а не от ресурсов.
Здравствуйте, 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 вам всё это придётся колхозить с нуля из говна и палок.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, 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 протоколе эта задача потребует настолько адских приседаний, что шансов получить под них бюджет очень мало.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, Буравчик, Вы писали:
Б>Передачу ключей идемпотентности, как и REST. И нужно явно позаботиться об этом, как и в REST.
Ну, то есть мы просто переизобретаем REST, только начинаем с более низкого старта.
Б>Интересно, что при проектировании приложения ты используешь анемик (ФП-стиль), но при проектировании API действуешь с точность до наоборот.
Не, анемик и ФП никак не связаны между собой. Ну, разве что statelesness. Анемика прекрасно работает с ООП — то есть интерфейсы, наследование, агрегация, специализация, вот это всё.
Наверное, можно анемик и на ФП залудить, но я так далеко заходить не намерен.
>Рассматривая соседнюю тему о расчете надбавки, вероятно, в API появидсяся бы ресурс "рассчитать надбавку" (ок, просто "надбавка"). Б>Но это и есть RPC-стиль, о котором я говорил выше. Работа от операций, а не от ресурсов.
Неа. Анемик как раз прекрасно ложится на REST — и наоборот.
Нет у нас никакого "рассчитать надбавку".
Есть просто GET /{resellerId}/prices — который умеет всё, что нужно типа conditional get, range header (с кастомными юнитами), а при необходимости и delta encoding.
На стороне сервера он стреляет в анемичный контроллер, который имеет доступ к DbContext, и подтаскивает список товаров вместе с применимыми к ним правилами формирования наценок.
Там прекрасно работает декомпозиция — например, мы можем вынести работу с правилами ценообразования в отдельный класс, которым будем пользоваться как из модуля "показ прайслиста", так и из модуля "обработки заказа".
"операция" в том смысле, который более-менее похож на RPC — это отправка заказа.
В зависимости от того, насколько я доверяю авторам клиентской части, я бы делал его либо через PUT, либо через POST.
При наличии выбора — естественно, через PUT.
Потому что у меня будет возможность обработать массу ситуаций предсказуемым образом. POST потребует дополнительных усилий, которые есть риск забыть сделать
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, Sharov, Вы писали:
S>А в http rest на отиличать не надо?
В HTTP у нас есть штатный способ.
200 Ok — всё в порядке
4xx — проблема с вашим запросом; повторять его нет смысла, пока вы не исправите проблему.
Подробности описываются кодом статуса + телом ответа.
5хх — проблема сервера; запрос, возможно, удастся повторить позже (+Retry-After, если известно, насколько позже).
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
В>>И если одназночность так и не пришла, валить сервер DDOS-ом? S>Откуда D DOS? Вы всё же в словаре-то смотрите незнакомые слова, прежде чем ими пользоваться
Телепат в студии? Откуда известно что и кому неизвестно?
Клиенты всегда сидят на одном и том же компьютере, сетке, городе, стране, планете? Да, всегда, но вполне могут быть распределены.
S>1. Со стороны сервера, вам в любом случае нужно думать о throttling. Потому что нет никакой гарантии, что клиенты ведут себя прилично, и не захотят вас просто завалить.
Во-первых, это явно не проблема разработчика, скажем честно.
Во-вторых, зачем создавать самому себе (и коллегам) проблему на ровном месте? Если пришёл 5xx — это почти всегда означает, что сервер не справился и почти всегда означает, что повторная попытка приведёт к тому же самому результату. Иключений так мало, что можно пренебречь и обрабатывать отдельно.
S>2. Со стороны клиента, достаточно брать паузу при ошибках. В реальной среде вы вряд ли получите DOS из-за проблем обратного канала: характерное время, за которое вы получаете таймаут — около 5 секунд (это оптимистично). Чаще делают таймауты в 30 секунд. "Долбя" сервер запросами раз в полминуты, вы никакого DOS не устроите.
Вообще не нужно, нужно сказать — ошибка, звоните в поддержку если чё и все дела. Ибо у вас падает сервер.
S>3. Самое главное: а какая альтернатива? Никакого способа сделать лучше в природе не существует. См. "проблема двух генералов".
Альтернатива не долбиться головой об стенку после того как поставил шишку.