Увеличение счетчика ресурсов в режиме RESTful: PUT vs POST - PullRequest
23 голосов
/ 15 сентября 2009

У меня есть ресурс, у которого есть счетчик. Для примера давайте назовем ресурс profile , а счетчик - это число просмотров для этого профиля.

Согласно REST wiki , запросы PUT должны использоваться для создания или изменения ресурса и должны быть идемпотентными. Эта комбинация хороша, если я обновляю, скажем, имя профиля, потому что я могу выдать запрос PUT, который устанавливает имя в 1000 раз, и результат не меняется.

Для этих стандартных запросов PUT у меня есть браузеры, которые делают что-то вроде:

PUT /profiles/123?property=value&property2=value2

Для увеличения счетчика, URL вызывается так:

PUT /profiles/123/?counter=views

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

Я ищу руководство / лучшую практику. Вы просто делаете это как POST?

Ответы [ 4 ]

11 голосов
/ 08 февраля 2012

Я думаю, что правильный ответ - использовать PATCH. Я не видел, чтобы кто-то еще рекомендовал использовать его для атомарного увеличения счетчика, но я считаю, что RFC 2068 очень хорошо говорит:

Метод PATCH похож на PUT за исключением того, что объект содержит список отличий оригинальной версии ресурса идентифицируется Request-URI и желаемым содержимым ресурса после того, как действие PATCH было применено. Список отличий в формате, определяемом типом носителя объекта (например, "application / diff") и ДОЛЖНЫ включать достаточную информацию, чтобы сервер для воссоздания изменений, необходимых для преобразования оригинала версия ресурса до нужной версии.

Итак, чтобы обновить количество просмотров профиля 123, я бы:

PATCH /profiles/123 HTTP/1.1
Host: www.example.com
Content-Type: application/x-counters

views + 1

Где тип носителя x-counters (который я только что придумал) состоит из нескольких строк кортежей field operator scalar. views = 500 или views - 1 или views + 3 все допустимы синтаксически (но могут быть семантически запрещены).

Я могу понять какое-то недовольство при создании еще одного типа носителя, но я скромно предлагаю, чтобы он был более правильным, чем альтернатива POST / PUT. Создание ресурса для поля с его собственным URI и особенно его собственными деталями (которые я на самом деле не храню, все, что у меня есть - целое число) звучит для меня неправильно и громоздко. Что делать, если мне нужно обслуживать 23 разных счетчика?

9 голосов
/ 15 сентября 2009

Альтернативой может быть добавление в систему другого ресурса для отслеживания просмотров профиля. Вы можете назвать это «Просмотр».

Просмотр всех просмотров профиля:

GET / анкеты / 123 / просмотры

Чтобы добавить просмотр в профиль:

POST / profile / 123 / viewings # здесь, вы бы отправили информацию, используя пользовательский тип носителя в теле запроса.

Чтобы обновить существующий Просмотр:

PUT / viewings / 815 # отправляет пересмотренные атрибуты Просмотр в теле запроса, используя созданный вами тип носителя.

Чтобы углубиться в детали просмотра:

GET / просмотров / 815

Чтобы удалить просмотр:

УДАЛИТЬ / просмотров / 815

Кроме того, поскольку вы запрашиваете рекомендации, убедитесь, что ваша RESTful-система управляется гипертекстом .

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

Вместо этого создайте тип носителя, который воплощает концепции, которые параметры пытаются моделировать. Дайте этому типу носителя краткое, однозначное и описательное имя. Затем запишите этот тип носителя. Реальная проблема предоставления параметров запроса в REST заключается в том, что эта практика часто приводит к внеполосной связи и, следовательно, к усилению связи между клиентом и сервером.

Тогда дайте вашей системе единый интерфейс. Например, добавление нового ресурса всегда является POST. Обновление ресурса всегда является PUT. Удаление - это УДАЛЕНИЕ, а получение - это ПОЛУЧЕНИЕ.

Самая сложная часть в REST - это понимание того, как типы медиа фигурируют в проектировании системы (это также та часть, которую Филдинг упустил из своей диссертации, потому что у него не хватило времени). Если вам нужен конкретный пример гипертекстовой системы, которая использует и изменяет типы носителей, см. Sun Cloud API .

0 голосов
/ 30 июня 2017

После оценки предыдущих ответов я решил, что PATCH не подходит, и для моих целей возиться с Content-Type для тривиальной задачи было нарушением принципа KISS . Мне нужно было только увеличить n + 1, поэтому я просто сделал это:

PUT /profiles/123$views
++

Где ++ - это тело сообщения, и контроллер интерпретирует его как команду увеличить ресурс на единицу.

Я выбрал $, чтобы разграничить поле / свойство ресурса, поскольку он является легальным подразделяющим и, для моих целей, казался более интуитивным, чем /, который, на мой взгляд, обладает атмосферой проходимости.

0 голосов
/ 03 июля 2015

Я думаю, что оба подхода Яника и Рича интересны. PATCH не обязательно должен быть безопасным или бессильным, но может быть более устойчивым к параллелизму. Решение Рича, безусловно, легче использовать в «стандартном» REST API.

См. RFC5789 :

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

Запрос PATCH может быть выдан таким образом, чтобы быть идемпотентным, что также помогает предотвратить плохие результаты от столкновений между двумя PATCH запрашивает один и тот же ресурс в течение аналогичного периода времени. Столкновения из нескольких запросов PATCH могут быть более опасными, чем PUT столкновения, потому что некоторые форматы патчей должны работать с известная базовая точка, иначе они повредят ресурс.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...