Подтвердить что ты не робот

Увеличение счетчика ресурсов в RESTful пути: PUT vs POST

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

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

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

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

Для приращения счетчика один вызывает такой URL:

PUT /profiles/123/?counter=views

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

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

4b9b3361

Ответ 1

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

Чтобы просмотреть все просмотры профиля:

GET/profiles/123/viewings

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

POST/profiles/123/viewings #here, вы должны отправить данные, используя пользовательский тип носителя в теле запроса.

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

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

Чтобы просмотреть подробные сведения о просмотре:

GET/viewings/815

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

DELETE/viewings/815

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

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

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

Затем дайте вашей системе единый интерфейс. Например, добавление нового ресурса всегда является POST. Обновление ресурса всегда является PUT. Удаление - DELETE, а getiing - GET.

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

Ответ 2

Я думаю, правильный ответ - использовать 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 разных счетчика?

Ответ 3

Я думаю, что оба подхода Янича и Богата очень интересны. Патч не должен быть безопасным или невосприимчивым, но может быть более надежным против concurrency. Богатое решение, безусловно, проще использовать в "стандартном" REST API.

См. RFC5789:

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

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

Ответ 4

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

PUT /profiles/123$views
++

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

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