REST, HTTP DELETE и параметры

135

Есть ли что-нибудь, отличное от RESTful, в предоставлении параметров для HTTP-запроса DELETE?


Мой сценарий таков, что я моделирую «Вы уверены, что хотите удалить это?» сценарий. В некоторых случаях состояние ресурса предполагает, что запрошенное удаление может быть недопустимым. Вы, наверное, сами можете представить сценарии, в которых требуется подтверждение удаления.

Мы приняли решение: передать параметр в запрос на удаление, чтобы указать, что можно продолжить удаление ("? Force_delete = true")

например

DELETE http://server/resource/id?force_delete=true

Я считаю, что он все еще успокаивает с тех пор:

(a) Семантика DELETE не изменяется - пользователь по-прежнему может отправить обычный запрос DELETE, но это может не сработать с 409, и в теле ответа будет объяснено, почему. Я говорю, что может потерпеть неудачу, потому что (по причинам, не заслуживающим объяснения) в некоторых случаях нет причин побуждать пользователя.

(b) В диссертации Роя нет ничего, что могло бы предположить, что это противоречит духу REST - почему это могло быть, поскольку HTTP - это только одна реализация REST, поэтому почему передача параметров HTTP имеет значение


Может ли кто-нибудь указать мне на окончательное утверждение, объясняющее причину, по которой это не RESTful?

По связанному с этим вопросу: если пользователь не указывает force_delete, я возвращаюсь 409 Conflict- это наиболее подходящий код ответа?


Следовать за

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

Во-первых, реализация, возможно, нарушает «Единый интерфейс» (см. Раздел 5.1.5 диссертации Роя.

Добавляя force_delete, мы добавляем дополнительное ограничение к уже четко определенному методу DELETE. Это ограничение имеет значение только для нас.

Вы также можете возразить, что это нарушает «5.1.2 Клиент-Сервер», поскольку диалог подтверждения действительно является проблемой пользовательского интерфейса, и, опять же, не все клиенты захотят подтвердить удаление.

Предложения кого-нибудь?

Крис МакКоли
источник
1
Ваш URL-адрес диссертации Роя содержит ")", что вызывает ошибку 404. ics.uci.edu/~fielding/pubs/disssment/rest_arch_style.htm работает.
NuclearPeon

Ответы:

78

Нет, это не RESTful. Единственная причина, по которой вы должны помещать глагол ( force_delete) в URI, - это необходимость перегрузки методов GET / POST в среде, где методы PUT / DELETE недоступны. Судя по использованию вами метода DELETE, это не так.

Код ошибки HTTP 409/Conflictследует использовать в ситуациях, когда существует конфликт, который не позволяет службе RESTful выполнить операцию, но все же существует вероятность того, что пользователь сможет разрешить конфликт самостоятельно. Подтверждение перед удалением (при отсутствии реальных конфликтов, препятствующих удалению) не является конфликтом как таковым, поскольку ничто не мешает API выполнить запрошенную операцию.

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

Два примера того, как это сделать в пользовательском интерфейсе:

  • pre-HTML5 : * показать пользователю диалоговое окно подтверждения JS и отправить запрос, только если пользователь его подтвердит
  • HTML5 : * используйте форму с действием УДАЛИТЬ, где форма будет содержать только кнопки «Подтвердить» и «Отменить» («Подтвердить» будет кнопкой отправки)

(*) Обратите внимание, что версии HTML до 5 не поддерживают методы PUT и DELETE HTTP изначально, однако большинство современных браузеров могут использовать эти два метода с помощью вызовов AJAX. См. Эту ветку для получения подробной информации о кросс-браузерной поддержке.


Обновление (на основе дополнительных исследований и обсуждений):

Сценарий, в котором службе потребуется наличие force_delete=trueфлага, нарушает единый интерфейс, как определено в диссертации Роя Филдинга. Кроме того, согласно HTTP RFC , метод DELETE может быть переопределен на исходном сервере (клиенте), подразумевая, что это не выполняется на целевом сервере (службе).

Таким образом, как только служба получает запрос DELETE, она должна обрабатывать его без необходимости какого-либо дополнительного подтверждения (независимо от того, действительно ли служба выполняет операцию).

Мышей
источник
2
Не могли бы вы объяснить, какое ограничение REST нарушается? Учитывая, что URI должны быть непрозрачными для клиента, почему вы считаете, что ожидания клиента не выполняются с использованием HTTP DELETE, которое удаляет один ресурс, но не может удалить другой. Я не уверен, что 409 - лучший код состояния для возврата, но, помимо того, что это немного странная реализация, я не могу найти никаких ограничений REST, которые нарушаются.
Даррел Миллер,
2
@Darrel: (imho) он нарушает единый интерфейс методом DELETE, который не работает в соответствии со стандартами HTTP. Рассмотрим REST-клиент, который предполагает наличие стандартной REST-службы - как служба сообщит клиенту, что ей нужно добавить force_delete=true? Согласно HTTP RFC, метод DELETE может быть переопределен на исходном сервере (клиенте), подразумевая, что это не выполняется на целевом сервере (службе). Итак, я понимаю, что как только служба получит запрос DELETE, она должна обработать его без какого-либо подтверждения (независимо от того, действительно ли служба выполняет операцию).
MicE
1
@Chris, к вашему второму пункту: да, я тоже так понимаю, т.е. состояние предполагает реальный конфликт, а не необходимость в подтверждении. Я только что заметил обновление, которое вы сделали в своем вопросе, и я согласен - пока я сам изучал его, я пришел к такому же выводу (что это нарушает единый интерфейс и что подтверждение должно выполняться на клиенте / пользовательском интерфейсе сторона). Я также наткнулся на очень интересную ветку
MicE
2
@MicE В значительной степени я согласен с вами, что это не лучший способ справиться с этим сценарием. Я просто немного придирчив к ярлыку «это не RESTful». Какое-то время здесь эту фразу бросали на все. Однако можно было бы определить правила для типа носителя, в которых говорится, что если вы попытаетесь УДАЛИТЬ ресурс и получите сообщение об ошибке (я бы сказал, что 403 запрещено, будет лучше, чем 409), тогда клиент должен попытаться УДАЛИТЬ на связанном ресурсе добавив "force_delete = true". В некотором смысле это немного похоже на авторизацию. Выполните GET, получите 401, добавьте заголовок auth и снова GET.
Даррел Миллер,
2
@Darrel: это очень хороший аргумент, спасибо. И я сам видел, как люди навешивают ярлык not RESTful . Может случиться так, что в настоящее время барьер между сервисами и веб-приложениями становится очень туманным, поэтому одни люди могут видеть это с точки зрения чисто сервисных услуг, в то время как другие видят это с точки зрения смешанных приложений / сервисов. Я считаю, что именно здесь в игру вступает настоящий вопрос о том, как сделать подтверждение. @Chris: обновлено - спасибо, сэр, за очень интересную тему и обсуждение!
MicE
35

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

Имеет ли смысл указывать force_delete = true, если бы это был API программы? Если бы кто-то писал сценарий для удаления этого ресурса, не хотели бы вы заставить его указать force_delete = true, чтобы фактически удалить ресурс?

Алекс Роквелл
источник
Первый абзац вашего ответа - это ваше мнение, и я уважаю его, но вы не указали на что-то в литературе, запрещающее использование такого URI - он по-прежнему определяет ресурс и используется наиболее подходящий HTTP-глагол. В ответ на ваши вопросы; да, это все равно имеет смысл (на мой взгляд). Я ожидаю, что сценарий (возможно, на основе CURL) будет учитывать ответ 409 и предлагать пользователю, как можно повторно отправить запрос - все на основе моего тела ответа
Крис МакКоли
Хороший момент в сравнении веб-API с программным API. Часто это хороший способ узнать, является ли API RESTful или нет.
Laurent
18

Это старый вопрос, но вот несколько комментариев ...

  1. В SQL команда DELETE принимает параметр «CASCADE», который позволяет указать, что зависимые объекты также должны быть удалены. Это пример параметра DELETE, который имеет смысл, но man rm может предоставить другие. Как эти случаи могут быть реализованы в REST / HTTP без параметра?
  2. @Jan, похоже, это устоявшееся соглашение, согласно которому часть пути URL-адреса идентифицирует ресурс, тогда как строка запроса - нет (по крайней мере, не обязательно). Примеров предостаточно: получение того же ресурса, но в другом формате, получение определенных полей ресурса и т. Д. Если мы рассматриваем строку запроса как часть идентификатора ресурса, невозможно иметь концепцию «разных представлений одного и того же ресурса». без обращения к не-RESTful механизмам, таким как согласование содержимого HTTP (что может быть нежелательно по многим причинам).
Шей Рожанский
источник
Спасибо, что добавили это в беседу, даже если это не так уж и много разговоров, поскольку длится годы.
silviot
6

В дополнение к ответу Алекса:

Обратите внимание, что http: // server / resource / id? Force_delete = true идентифицирует ресурс, отличный от http: // server / resource / id . Например, огромная разница, удаляете ли вы / customers /? Status = old или / customers /.

январь

Ян Альгермиссен
источник
Я не согласен, я могу предоставить несколько URI для идентификации одного и того же ресурса.
Крис МакКоли,
19
Ага, каждый волен натворить беспорядок :-)
Ян Алджермиссен
В этом может помочь указание канонических URI: googlewebmastercentral.blogspot.com/2009/02/…
MicE
@Chris Должен быть только один URI, возвращающий представление ресурса. Другие URI могут относиться к той же концепции, но выполнение GET должно возвращать 303 See Other. И чтобы противостоять очевидному возражению против этого, /foo.xml и /foo.json - это два разных ресурса.
Даррел Миллер
@Darrell - согласен, но формат здесь не проблема. Также .format является соглашением в Rails и других фреймворках, не являющихся частью REST - вы должны использовать согласование содержимого в HTTP с MIME или микроформатами, чтобы полностью реализовать это.
Крис МакКоли,