Снова про глаголы в REST...
От: Shmj Ниоткуда  
Дата: 19.09.22 20:23
Оценка:
Многие против.

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

Можно так:

POST orders/1/confirm


Но тут не работа с сущностью.

Каноничнее будет так:

PATCH orders/1
   body: {"state": "confirmed"}


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

Еще пример:

POST notifications/1/resend


Ясно что переотправка оповещения. К примеру, если не пришло СМС — отправить повторно (считаем что на сервере по какой-либо причине статус отпавки — не определено и вынуждены доверять пользователю после 30 сек.).

Не комильфо. По канону будет так:

POST notifications/1/sending-attempt


Т.е. как бы создаем новую попытку отправки. По идее и таблицу попыток нужно бы добавить, но можно пока и без таблицы — главное API.

Как вы на все это смотрите?
Re: Снова про глаголы в REST...
От: vsb Казахстан  
Дата: 19.09.22 20:54
Оценка: +2
Ты или придерживается REST и тогда используешь его как положено, либо не придерживаешься и делаешь всё как бог на душу положит. Тут нет правильного или не правильного ответа, просто не надо называть вещи не своими именами.

Вроде как у тебя понимание REST есть, но "теряется ясность мысли" — это я не понимаю. Что значит теряется. REST это не про ясность, это про определённые гарантии, в основном про идемпотентность. То бишь можно ли данный запрос повторять, если возникла ошибка или нельзя.
Re[2]: Снова про глаголы в REST...
От: Shmj Ниоткуда  
Дата: 19.09.22 21:02
Оценка:
Здравствуйте, vsb, Вы писали:

vsb>Вроде как у тебя понимание REST есть, но "теряется ясность мысли" — это я не понимаю. Что значит теряется. REST это не про ясность, это про определённые гарантии, в основном про идемпотентность. То бишь можно ли данный запрос повторять, если возникла ошибка или нельзя.


См. второй пример — оба варианта POST. Вопрос в другом — глагол или имя существительное.

В первом примере POST и PATCH. Оба считаются не идемпотентыми.
Отредактировано 19.09.2022 21:04 Shmj . Предыдущая версия .
Re[3]: Снова про глаголы в REST...
От: vsb Казахстан  
Дата: 19.09.22 21:12
Оценка: +1
PATCH обычно должен быть идемпотентным. В твоём случае нет никакой причины ему быть не-идемпотентным.

POST во втором случае не нужен. Делай PUT notifications/1/attempt/{uuid} и повторяй его, если получена ошибка (кроме 4xx).

Глаголы в REST не применимы.

Можешь сообразить что-то вроде

PATCH notifications/1

{ "op": "add", "path": "attempts" }

это как раз пример не-идемпотентного PATCH. Но по-мне такой дизайн не нужен. Лучше уж POST notifications/1/resend.
Отредактировано 19.09.2022 21:20 vsb . Предыдущая версия . Еще …
Отредактировано 19.09.2022 21:19 vsb . Предыдущая версия .
Отредактировано 19.09.2022 21:16 vsb . Предыдущая версия .
Re: Снова про глаголы в REST...
От: rosencrantz  
Дата: 19.09.22 21:17
Оценка:
Здравствуйте, Shmj, Вы писали:

S>Но здесь минус — теряется ясность мысли.


S>Как вы на все это смотрите?


Как уже выше отметили, практическая ценность REST только в идемпотентности по большому счёту. Что там тебе кажется логичным и последовательным в именовании — это твоя личная "логичность и последовательность", не стоит заблуждаться по этому поводу.

Если мне от твоего сервиса что-то надо, я к тебе приду и спрошу что там надо дёргать (потому что во-первых см. выше, во-вторых стопудово документации нет). Если тебе так не нравится — задокументируй, читаю я хорошо
Re[4]: Снова про глаголы в REST...
От: Shmj Ниоткуда  
Дата: 19.09.22 21:36
Оценка:
Здравствуйте, vsb, Вы писали:

vsb>PATCH обычно должен быть идемпотентным.


Вы путаете с PUT:

A PATCH is not necessarily idempotent, although it can be. Contrast this with PUT; which is always idempotent.

https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/PATCH



  Скрытый текст
https://19yw4b240vb03ws8qm25h366-wpengine.netdna-ssl.com/wp-content/uploads/Understanding-Idempotency-and-Safety-in-API-Design.png


vsb>В твоём случае нет никакой причины ему быть не-идемпотентным.


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

vsb>POST во втором случае не нужен. Делай PUT notifications/1/attempt/{uuid} и повторяй его, если получена ошибка (кроме 4xx).


Ключ идемпотентности можно применить и к POST. Вкусовщина.
Re[2]: Снова про глаголы в REST...
От: Shmj Ниоткуда  
Дата: 19.09.22 21:39
Оценка: 5 (1)
Здравствуйте, rosencrantz, Вы писали:

R>Как уже выше отметили, практическая ценность REST только в идемпотентности по большому счёту.


Идемпотентность не специфична только для REST.

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


Ну почему же мне?

Вот пример: https://betterprogramming.pub/22-best-practices-to-take-your-api-design-skills-to-the-next-level-65569b200b9

См. практику 6. Use Verbs for Non-Resource URL
Re[5]: Снова про глаголы в REST...
От: vsb Казахстан  
Дата: 19.09.22 21:59
Оценка:
Здравствуйте, Shmj, Вы писали:

vsb>>PATCH обычно должен быть идемпотентным.


S>Вы путаете с PUT:


S>

S>A PATCH is not necessarily idempotent, although it can be. Contrast this with PUT; which is always idempotent.

S>https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/PATCH


Не путаю. Я поэтому и написал "обычно". Да, можно спроектировать API, в котором PATCH не-идемпотентен (я привёл такой пример в своём сообщении). Хотя лично я считаю, что это ошибка и такие API проектировать не надо. PUT и PATCH нужно делать идемпотентными, а все не-идемпотентные операции переложить на POST и там можно даже не притворяться, что у нас REST, а просто писать, как удобно, всё равно там никаких гарантий. Но в идеале таких операций быть не должно.

vsb>>В твоём случае нет никакой причины ему быть не-идемпотентным.


S>Подтвердить заказ, который только что отменили — должно вызвать ошибку.


Это можно о любой операции сказать. Идемпотентность не означает, что эта операция всегда срабатывает. PUT тоже не будет работать, если это нарушает какие-то условия уникальности, к примеру. Если возникают проблемы, ты возвращаешь ошибку 4xx, которую уже можно и нужно показывать пользователю в каком-то виде, ну или ещё как-то обрабатывать, но не повторять,

S>Ключ идемпотентности можно применить и к POST. Вкусовщина.


Можно, но принято эту семантику накладывать на PUT.
Re[3]: Снова про глаголы в REST...
От: rosencrantz  
Дата: 19.09.22 22:39
Оценка:
Здравствуйте, Shmj, Вы писали:

S>Идемпотентность не специфична только для REST.


Даже и не пытался спорить.

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


S>Ну почему же мне?


S>Вот пример: https://betterprogramming.pub/22-best-practices-to-take-your-api-design-skills-to-the-next-level-65569b200b9


S>См. практику 6. Use Verbs for Non-Resource URL


Даже и не пытался спорить. Я про твои логичные последовательные попытки нагородить эту онтологию из confirmation, notification, notification-attempt, и т.д.
Re: Снова про глаголы в REST...
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 19.09.22 22:48
Оценка:
Здравствуйте, Shmj, Вы писали:

S>Как вы на все это смотрите?


POST orders/1/confirm()
POST notifications/1/resend()


не благодарите
Re: Снова про глаголы в REST...
От: DiPaolo Россия  
Дата: 20.09.22 02:15
Оценка: 12 (1) +1
S>Как вы на все это смотрите?

Спокойно отношусь к такому

Пояснения:

  Уместно будет вспомнить байку про goto
Стадии профессионального развития разработчика.

1. следует правилу от более опытных коллег "никогда не используй goto"
2. иногда, если нужно, можно использовать goto
3. наставляет молодых коллег словами "никогда не используй goto"


Конкретно по примерам.

S>
S>POST orders/1/confirm
S>


Я бы сделал (в порядке убывания вероятности):

1.
PUT orders/1/status
body
{
    "status": "confirmed"
}


2.
PUT orders/1/confirm


3.
GET orders/1/changeStatus?status=confirmed


S>
S>POST notifications/1/resend
S>


Я бы сделал одним из следующих вариантов (как конкретно — зависит от контекста и способов применения вызовов):

1.
POST notifications/clone
body
{
    "fromId": 1
}


2.
POST notifications
body
{
    тут вручную созданный клон нотификации с ID=1
}


3.
POST notifications/1/operations
body
{
    "operation": "resend"
}


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

В случае, когда делаем публичный АПИ, который идет на продажу, либо им будут пользоваться тысячи клиентов опен-осерса, то имеет смысл потратить больше времени на обдумывания и приведения к "более каноничному" стилю.
Патриот здравого смысла
Re[6]: Снова про глаголы в REST...
От: Shmj Ниоткуда  
Дата: 20.09.22 04:35
Оценка:
Здравствуйте, vsb, Вы писали:

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


vsb>>>PATCH обычно должен быть идемпотентным.


S>>Вы путаете с PUT:


S>>

S>>A PATCH is not necessarily idempotent, although it can be. Contrast this with PUT; which is always idempotent.

S>>https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/PATCH


vsb>Не путаю. Я поэтому и написал "обычно". Да, можно спроектировать API, в котором PATCH не-идемпотентен (я привёл такой пример в своём сообщении). Хотя лично я считаю, что это ошибка и такие API проектировать не надо. PUT и PATCH нужно делать идемпотентными, а все не-идемпотентные операции переложить на POST и там можно даже не притворяться, что у нас REST, а просто писать, как удобно, всё равно там никаких гарантий. Но в идеале таких операций быть не должно.


А почему POST вы не хотите делать идемпотентным, ведь тоже можно и Яндекс так делает. Просьба высказаться тут: https://rsdn.org/forum/dotnet/8364021.flat
Автор: Shmj
Дата: 20.09 07:26


S>>Подтвердить заказ, который только что отменили — должно вызвать ошибку.


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


PUT должен отработать всегда — какая уникальность? Если сущность с таким ключом существует — то просто заменяете ее и все. Если нельзя заменить — то не обманывайте не притворяйтесь PUT-ом.

S>>Ключ идемпотентности можно применить и к POST. Вкусовщина.

vsb>Можно, но принято эту семантику накладывать на PUT.

Тут: https://rsdn.org/forum/dotnet/8364021.flat
Автор: Shmj
Дата: 20.09 07:26
Re[4]: Снова про глаголы в REST...
От: Shmj Ниоткуда  
Дата: 20.09.22 04:36
Оценка:
Здравствуйте, rosencrantz, Вы писали:

S>>Вот пример: https://betterprogramming.pub/22-best-practices-to-take-your-api-design-skills-to-the-next-level-65569b200b9


S>>См. практику 6. Use Verbs for Non-Resource URL


R>Даже и не пытался спорить. Я про твои логичные последовательные попытки нагородить эту онтологию из confirmation, notification, notification-attempt, и т.д.


Это не мои попытки — это рекомендации многих уважаемых авторитетов. Ссылку вам дал.

Если авторитеты говорят — значит это всем должно быть понятно и проблем не вызовет. Когда городишь отсебятину — тогда да, сложно будет понять что ты там нагенерил в своей голове.
Re[2]: Снова про глаголы в REST...
От: Shmj Ниоткуда  
Дата: 20.09.22 04:38
Оценка:
Здравствуйте, gandjustas, Вы писали:

G>
G>POST orders/1/confirm()
G>POST notifications/1/resend()
G>


G>не благодарите


А а на чем основано ваше предложение? Идет ли оно в соответствие со стандартами и/или рекомендациями авторитетов или просто отсебятина?
Re[2]: Снова про глаголы в REST...
От: Shmj Ниоткуда  
Дата: 20.09.22 04:51
Оценка:
Здравствуйте, DiPaolo, Вы писали:

DP>это обычно обходится быстрее и дешевле, т.к. меньше времени уходит на буквоедство, а фичи быстрее появляются в продакшене; сам проходил через это, когда обсуждали очень долго как лучше назвать, какой глагол (GET/PUT/PATCH) использовать, как правильно/не правильно, вместо того, чтобы забить на это и сделать так, как НАМ удобно


Это да, но кроме создания проекта — вы нарабатываете хороший стиль кодирования. Т.е. привыкаете сразу либо делать правильно, либо делать не правильно. В будущем вы всегда будете делать как привыкли и тратить время одинаково либо на понятный стиль либо на непонятный никому кроме вас — просто как привыкните. До пенсии лет 25 еще есть, по этому раз 10 придется еще писать API — есть смысл наработать стиль. А может еще и на пенсии что-то придется писать. Смысл есть.

DP>Я бы сделал (в порядке убывания вероятности):


DP>1.

DP>
DP>PUT orders/1/status
DP>body
DP>{
DP>    "status": "confirmed"
DP>}
DP>


Почему не PATCH?

DP>Опять же, самое главное: чтобы была прописана договоренность бэка и фронта, как максимально удобно и тем и другим, и второе — придерживаться консистентности в рамках одного АПИ.


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

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


Будешь меньше тратить времени, если сейчас заморочишься с этими вопросами.
Отредактировано 20.09.2022 4:57 Shmj . Предыдущая версия .
Re[7]: Снова про глаголы в REST...
От: vsb Казахстан  
Дата: 20.09.22 04:55
Оценка:
Здравствуйте, Shmj, Вы писали:

S>PUT должен отработать всегда — какая уникальность? Если сущность с таким ключом существует — то просто заменяете ее и все. Если нельзя заменить — то не обманывайте не притворяйтесь PUT-ом.


Про то, что PUT должен отработать всегда — я в первый раз слышу. PUT /resource1/{resource1Id}/resource2/{resource2Id} тоже должен отработать всегда, создавая resource1 если он был удалён?

В общем не согласен. Всегда есть правила валидации и они могут изменяться во времени.
Re[8]: Снова про глаголы в REST...
От: Shmj Ниоткуда  
Дата: 20.09.22 05:07
Оценка:
Здравствуйте, vsb, Вы писали:

vsb>В общем не согласен. Всегда есть правила валидации и они могут изменяться во времени.


Как вы считаете, почему PUT гарантированно идемпотентен а PATCH — нет?

Выше вы писали:

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


Т.е. имели ли вы в виду, что первый запрос PUT — сработал, т.к. записи с таким ID не было. А второй PUT — уже не сработал, т.к. запись с таким ID уже есть в системе? Или о какой уникальности речь?
Re[3]: Снова про глаголы в REST...
От: DiPaolo Россия  
Дата: 20.09.22 05:07
Оценка: +1
S>Т.е. привыкаете сразу либо делать правильно, либо делать не правильно.

В РЕСТе нет такого: правильно/неправильно. Есть рекомендации.

S>В будущем вы всегда будете делать как привыкли и тратить время одинаково либо на понятный стиль либо на непонятный никому кроме вас — просто как привыкните.


Ну я ж специально по этому поводу два раза подчеркнул: важно прописать стиль и придерживаться его.

S>До пенсии лет 25 еще есть, по этому раз 10 придется еще писать API — есть смысл наработать стиль. А может еще и на пенсии что-то придется писать. Смысл есть.


Ну вот все что я вам написал выше — оно уже основано на многолетнем опыте написания АПИ, и не только РЕСТа.

S>Почему не PATCH?


Меньше мороки. Фронтам скорее всего проще будет использовать.

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


Обычно, но не всегда. Команды бывают разные. Еще раз — РЕСТ — это НЕ стандарт.

S>Будешь меньше тратить времени, если сейчас заморочишься с этими вопросами.


Да какими вопросами? Вы из мухи слона делаете. Каким бы важным вам не казалось то, о чем вы сейчас спрашиваете, это — мелочь в масштабах продукта. И вот с опытом как раз приходит понимание, что важно и на что имеет смысл тратить больше времени, а что неважно.

Сразу хочется вспомнить "вам шашечки или ехать?". Программистам свойственен перфекционизм, а многие любят программировать ради программирования. И если их не ограничивать, они могут месяцами "вырабатывать стиль", переписывать с более лучшим дизайном, до посинения вылизывать АПИ. Продукт при этом будет стоять на месте.
Патриот здравого смысла
Re[9]: Снова про глаголы в REST...
От: vsb Казахстан  
Дата: 20.09.22 05:59
Оценка: 1 (1) +2
Здравствуйте, Shmj, Вы писали:

vsb>>В общем не согласен. Всегда есть правила валидации и они могут изменяться во времени.


S>Как вы считаете, почему PUT гарантированно идемпотентен а PATCH — нет?


Потому, что те, кто придумывали эти ассоциации между методами и идемпотентностью, так решили. На мой взгляд это решение было неправильным и я в своём коде это ужесточаю до требований 100% идемпотентности в PATCH.

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


S>Т.е. имели ли вы в виду, что первый запрос PUT — сработал, т.к. записи с таким ID не было. А второй PUT — уже не сработал, т.к. запись с таким ID уже есть в системе? Или о какой уникальности речь?


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

PUT /users/1/message/2
DELETE /users/1
PUT /users/1/message/2

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

Может и второй PUT не сработать, если параметры отличаются. Хотя стандарты и говорят, что PUT заменяет данные, но это же не значит, что я обязан менять бизнес-логику под эти стандарты. К примеру у меня поле не должно меняться после создания. В этом случае второй PUT вернёт ошибку, если поля в базе отличаются от тех, что он пытается изменить. На самом деле я обычно так и делаю — PUT два раза подряд сработает только если параметры одинаковые. Не думаю, что это нарушает REST. А для редактирования уже PATCH.
Отредактировано 20.09.2022 6:03 vsb . Предыдущая версия .
Re[10]: Снова про глаголы в REST...
От: Shmj Ниоткуда  
Дата: 20.09.22 07:26
Оценка:
Здравствуйте, vsb, Вы писали:

vsb>На самом деле я обычно так и делаю — PUT два раза подряд сработает только если параметры одинаковые.


Хорошо, очень интересно.

Такой вариант. PUT 2 раза подряд, параметры 100% одинаковые. Между двумя запросами никаких DELETE и пр. не было, т.е. все чисто. Но в PUT указано состояние Created. Однако когда пришел второй PUT — система в фоновом режиме начала обработку операции и изменила состояние на Processing, что значит заказ клиента начал исполняться и вернуть все в начальное состояние Created, как того требует второй PUT — никоим образом не представляется возможным. Что делать? Просто проигнорите и вернете 200, как бы подразумевая, что клиент использует PUT в качестве создания записи, а раз запись уже создана и хотя состояние изменилось — то все ОК. Или же вернете какую-то ошибку?
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.