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

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

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

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

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

Если расскажете, большое спасибо.
Если не расскажите, просто спасибо, что дочитали
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[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[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: 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: прохой\хороший интерфейс
От: 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[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[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[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 нам не нужен. В общем, это всё примерно как задача "а спроектируйте мне иерархию классов, описывающую квадрат, прямоугольник, круг, и эллипс".
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.