Rest uri design для изменения статуса ресурса

У меня есть ресурс, который может быть доступен в URI /resources/{resource_identifier}, и у него есть свойство status, которое я хочу быть доступным. Я подумал о нескольких вариантах этого, что было бы "лучшим" или "самым RESTfull"?

Вариант 1 Добавление действий в URI и наличие клиента POST для этих URI

/resources/{resource_identifier}/void    
/resources/{resource_identifier}/open    
/resources/{resource_identifier}/close

Это выглядит неуклюже.


Вариант 2 Используйте параметр запроса в URI и поставьте клиенту PATCH на эти

/resources/{resource_identifier}?transition=void
/resources/{resource_identifier}?transition=open
/resources/{resource_identifier}?transition=close

Вариант три Используйте полезную нагрузку запроса и у клиента PUT

/resources/{resource_identifier}

параметры полезной нагрузки:

{ ..., "status" :"void" }
{ ..., "status" :"open" }
{ ..., "status" :"close" }

Или может быть что-то еще?

Ответ 1

Первый вариант явно не REST; вы имеете "действия" в URI и используете POST, который должен создать новый ресурс, который вы явно не пытаетесь сделать.

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

Если мы рассмотрим метод запроса. В моей книге это довольно просто, я полагаю, что статус - это только одно поле этого ресурса, поэтому, если вы делаете только частичное обновление, вы исправляете ресурс, и поэтому PATCH - это метод, который следует использовать. В случае случайности "статус" является единственным свойством, тогда изменение статуса полностью меняет ресурс, и поэтому PUT будет приемлемым; но я сомневаюсь, что это действительно так.

В соответствии с этим, URI третьего варианта, в сочетании с использованием PATCH, вероятно, являются лучшим вариантом.

PATCH /resources/{resource_identifier}

{ "status" :"close" }

Конечно, вы могли бы также объединить это с концепцией раскрытия определенных атрибутов через свой собственный URI, как если бы они были самим ресурсом. Честно говоря, мне это не нравится, поскольку оно кажется довольно странным и работает только по одному атрибуту за раз. Тем не менее, если это то, что вы хотели использовать, вы могли бы иметь что-то вроде:

PUT /resources/{resource_identifier}/status

close

Имейте в виду, что нет "правильного" способа сделать REST, просто "неплохо". Это стиль, а не набор правил.

Я также предлагаю вам подумать, что возможность принимать многие форматы является желательной особенностью, вообще говоря. Таким образом, первый вариант, как правило, легче работать. Вы можете взять JSON, как в примере, или обменять его на XML <status>close</ status>, или пару пары ключей status=closed и т.д.

Ответ 2

Почему бы не иметь "статус" в качестве ресурса. Вы можете управлять им. Также предположите, что уже существует статус "статус", созданный как часть создания ресурса {resource_identifier}, и для статуса уже есть значение по умолчанию.

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

обновляется Перенос состояния на тело-пульт

PUT:    /resources/{resource_identifier}/status/

Body: {void | open | close }

Ответ 3

Второй вариант выглядит лучше, потому что вы поддерживаете структуру URL-адреса RESTful и не добавляете методы стиля RPC в конец.

Почему бы просто не сделать это:

PUT до /resources/:id и отправьте данные transition=void с запросом.

Он ведет себя так же, как если бы вы получали запрос POST, просто извлеките данные из тела запроса.

Ответ 4

Есть много случаев, когда изменения состояния имеют много бизнес-логики. Хотя ответы основаны на "стандартах отдыха", я думаю, что есть случаи, которые не просто меняют поле состояния.

Например, если система должна отменить заказ. Это не просто изменить состояние, так как порядок имеет много состояний, и каждое изменение представляет собой много логики (уведомления, проверки и т.д.)

В случаях использования:

PATCH /order/1
{ "status" :"cancelled" }

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

Я считаю, что проще иметь метод отмены и выполнять свою работу. Я думаю, что во многих случаях это более элегантно:

PATCH: /order/1/cancel 

//you could use the body with some cancellation data.

Вам может помочь следующая ссылка: https://phauer.com/2015/restful-api-design-best-practices/#keep-business-logic-on-the-server-side