Должен ли я использовать PATCH или PUT в моем REST API?

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

Есть группа. Каждая группа имеет статус. Группа может быть активирована или деактивирована администратором.

Должен ли я разработать свою конечную точку как

PUT /groups/api/v1/groups/{group id}/status/activate

ИЛИ ЖЕ

PATCH /groups/api/v1/groups/{group id}

with request body like 
{action:activate|deactivate}

Ответ 1

Метод PATCH является правильным выбором, так как вы обновляете существующий ресурс - идентификатор группы. PUT следует использовать только в том случае, если вы полностью заменяете ресурс.

Дополнительная информация о частичной модификации ресурса доступна в RFC 5789. В частности, метод PUT описывается следующим образом:

Некоторым приложениям, расширяющим протокол передачи гипертекста (HTTP), требуется функция для частичной модификации ресурса. Существующий метод HTTP PUT позволяет только полную замену документа. Это предложение добавляет новый метод HTTP, PATCH, для изменения существующего ресурса HTTP.

Ответ 2

R в REST означает ресурс

(Который не соответствует действительности, потому что он обозначает Репрезентационный, но это хорошая уловка, чтобы помнить о важности ресурсов в REST).

О PUT/groups/api/v1/groups/{group id}/status/activate: вы не обновляете "активировать". "Активировать" - это не вещь, это глагол. Глаголы никогда не являются хорошим ресурсом. Практическое правило: если действие, глагол, находится в URL, это, вероятно, не RESTful.

Что ты делаешь вместо этого? Либо вы "добавляете", "удаляете" или "обновляете" активацию в группе, либо, если хотите, манипулируете "состоянием" -resource в группе. Лично я бы использовал "активации", потому что они менее неоднозначны, чем понятие "статус": создание статуса неоднозначно, создание активации - нет.

  • POST/groups/{group id}/activation Создает (или запрашивает создание) активацию.
  • PATCH/groups/{group id}/activation Обновляет некоторые детали существующей активации. Поскольку группа имеет только одну активацию, мы знаем, на какую активацию -resource мы ссылаемся.
  • PUT/groups/{group id}/activation Вставляет или заменяет старую активацию. Поскольку группа имеет только одну активацию, мы знаем, на какую активацию -resource мы ссылаемся.
  • DELETE/groups/{group id}/activation Отменит или удалит активацию.

Этот шаблон полезен, когда "активация" группы имеет побочные эффекты, такие как осуществляемые платежи, отправка почты и т.д. Только POST и PATCH могут иметь такие побочные эффекты. Когда, например, удаление активации должно, скажем, уведомлять пользователей по почте, DELETE не является правильным выбором; в этом случае вы, вероятно, захотите создать ресурс деактивации: POST/groups/{group_id}/deactivation.

Рекомендуется следовать этим рекомендациям, потому что этот стандартный контракт очень четко разъясняет вашим клиентам, и все прокси и уровни между клиентом и вами знают, когда безопасно повторять, а когда нет. Допустим, клиент находится где-то с нестабильным Wi-Fi, и его пользователь нажимает "деактивировать", что вызывает DELETE: если это не удается, клиент может просто повторить попытку, пока он не получит 404, 200 или что-либо еще, что он может обработать. Но если он запускает POST to deactivation он знает, что не нужно повторять: POST подразумевает это.
У любого клиента теперь есть контракт, который, при соблюдении которого, защитит от отправки 42 электронных писем "ваша группа была деактивирована" просто потому, что его HTTP-библиотека продолжала повторять вызов к бэкэнду.

Обновление одного атрибута: используйте PATCH

PATCH/groups/{group id}

В случае, если вы хотите обновить атрибут. Например, "статус" может быть атрибутом в группах, который можно установить. Такой атрибут, как "статус", часто является хорошим кандидатом для ограничения белым списком значений. Примеры используют некоторую неопределенную JSON-схему:

PATCH /groups/{group id} { "attributes": { "status": "active" } }
response: 200 OK

PATCH /groups/{group id} { "attributes": { "status": "deleted" } }
response: 406 Not Acceptable

Заменив ресурс, без побочных эффектов используйте PUT.

PUT/groups/{group id}

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

Клиент должен, в случае запроса PUT, всегда отправлять весь ресурс, имея все данные, необходимые для создания нового элемента: обычно те же данные, что и для POST-create.

PUT /groups/{group id} { "attributes": { "status": "active" } }
response: 406 Not Acceptable

PUT /groups/{group id} { "attributes": { "name": .... etc. "status": "active" } }
response: 201 Created or 200 OK, depending on whether we made a new one.

Очень важным требованием является то, что PUT является идемпотентом: если вам требуются побочные эффекты при обновлении группы (или изменении активации), вам следует использовать PATCH. Поэтому, когда обновление приводит, например, к отправке почты, не используйте PUT.

Ответ 3

Я бы рекомендовал использовать PATCH, потому что ваша группа ресурсов имеет много свойств, но в этом случае вы обновляете только поле активации (частичная модификация)

в соответствии с RFC5789 (https://tools.ietf.org/html/rfc5789)

Существующий метод HTTP PUT позволяет полностью заменить документ. Это предложение добавляет новый HTTP-метод PATCH для изменения существующий ресурс HTTP.

Кроме того, более подробно

Разница между запросами PUT и PATCH отражается в способ, которым сервер обрабатывает закрытый объект для изменения ресурса
идентифицированных Request-URI. В запросе PUT закрытый объект считается измененной версией ресурса, хранящегося на сайте исходного сервера, и клиент запрашивает, чтобы сохраненная версия
быть заменен. Однако с помощью PATCH закрытый объект содержит набор инструкций, описывающих, как ресурс, находящийся в настоящее время на сайте исходный сервер должен быть изменен для создания новой версии. ПУТЬ метод влияет на ресурс, идентифицированный Request-URI, и он также МОГУТ иметь побочные эффекты на другие ресурсы; то есть новые ресурсы
могут быть созданы или уже изменены, с помощью приложения PATCH.

PATCH не является ни безопасным, ни идемпотентным, как определено в [RFC2616], Раздел    9.1.

Клиенты должны выбирать, когда использовать PATCH, а не PUT. Для
Например, если размер патч-документа больше размера новые данные ресурсов, которые будут использоваться в PUT, тогда это может сделать смысл использовать PUT вместо PATCH. Сравнение с POST еще больше сложно, потому что POST используется по-разному и может включать операции PUT и PATCH, если сервер выбирает. Если
операция не изменяет ресурс, идентифицированный Request- URI предсказуемым образом, вместо PATCH следует рассматривать POST или PUT.

Код ответа для PATCH

Код ответа 204 используется, потому что ответ не несет    тела сообщения (который ответ с кодом 200 имел бы). Заметка    что другие коды успеха также могут быть использованы.

также ссылаются на thttp://restcookbook.com/HTTP%20Methods/patch/

Предостережение: API, реализующий PATCH, должен патч атомарно. Он НЕ ДОЛЖЕН возможно, что ресурсы будут частично исправлены по запросу GET.

Ответ 4

Поскольку вы хотите создать API, используя архитектурный стиль REST, вам нужно подумать о своих вариантах использования, чтобы решить, какие концепции достаточно важны, чтобы раскрывать их как ресурсы. Если вы решите выявить статус группы в качестве под-ресурса, вы можете дать ей следующий URI и реализовать поддержку методов GET и PUT:

/groups/api/groups/{group id}/status

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

Если вы решите выставить статус как под-ресурс группы, он должен быть ссылкой в ​​представлении группы. Например, если агент получает группу 123 и принимает XML, тело ответа может содержать:

<group id="123">
  <status>Active</status>
  <link rel="/linkrels/groups/status" uri="/groups/api/groups/123/status"/>
  ...
</group>

Гиперссылка необходима для выполнения гипермедиа как состояния состояния приложения в архитектурном стиле REST.

Ответ 5

Обычно я предпочитаю что-то более простое, например, activate/deactivate подресурс (связанный заголовком Link с помощью rel=service).

POST /groups/api/v1/groups/{group id}/activate

или же

POST /groups/api/v1/groups/{group id}/deactivate

Для потребителя этот интерфейс предельно прост, и он следует принципам REST, не увязая вам в концептуализации "активаций" как отдельных ресурсов.