RESTful альтернативы DELETE тела запроса
Хотя спецификация HTTP 1.1, по- видимому, разрешает тела сообщений для запросов DELETE, это, похоже, указывает на то, что серверы должны игнорировать ее, поскольку для нее нет определенной семантики.
4.3 Тело сообщения
Сервер ДОЛЖЕН прочитать и переслать тело сообщения по любому запросу; если метод запроса не включает определенную семантику для тела объекта, то тело сообщения ДОЛЖНО игнорироваться при обработке запроса.
Я уже рассмотрел несколько связанных обсуждений на эту тему в SO и за ее пределами, таких как:
- Разрешено ли тело объекта для запроса HTTP DELETE?
- Полезные нагрузки методов HTTP-запроса
- HTTP GET с телом запроса
Кажется, что большинство обсуждений сходятся во мнении, что предоставление тела сообщения на DELETE может быть разрешено, но обычно это не рекомендуется.
Кроме того, я заметил тенденцию в различных клиентских библиотеках HTTP, когда все больше и больше улучшений регистрируются в этих библиотеках для поддержки тел запросов в DELETE. Большинство библиотек кажутся обязательными, хотя иногда с небольшим начальным сопротивлением.
Мой вариант использования требует добавления некоторых требуемых метаданных в DELETE (например, "причина" удаления, наряду с некоторыми другими метаданными, необходимыми для удаления). Я рассмотрел следующие варианты, ни один из которых не представляется полностью подходящим и не согласуется со спецификациями HTTP и / или рекомендациями REST:
- Тело сообщения - спецификация указывает, что тела сообщения в DELETE не имеют семантического значения; не полностью поддерживается клиентами HTTP; нестандартная практика
- Пользовательские заголовки HTTP - Требование пользовательских заголовков, как правило, противоречит стандартной практике; их использование несовместимо с остальной частью моего API, ни один из которых не требует пользовательских заголовков; кроме того, нет хорошего HTTP-ответа для обозначения неверных пользовательских значений заголовка (возможно, это отдельный вопрос)
- Стандартные заголовки HTTP - стандартные заголовки не подходят
- Параметры запроса - Добавление параметров запроса фактически изменяет удаляемый Request-URI; против стандартных практик
- Метод POST - (например,
POST /resourceToDelete { deletemetadata }
) POST не является семантической опцией удаления; Фактически POST представляет желаемое противоположное действие (т.е. POST создает подчиненных ресурсов; но мне нужно удалить ресурс) - Несколько методов - Разделение запроса DELETE на две операции (например, PUT delete metadata, затем DELETE) разделяет элементарную операцию на две, что может привести к несогласованному состоянию. Причина удаления (и другие связанные метаданные) не являются частью самого представления ресурса.
Моим первым предпочтением, вероятно, было бы использование тела сообщения, а затем пользовательских заголовков HTTP; однако, как указано, у этих подходов есть некоторые недостатки.
Существуют ли какие-либо рекомендации или рекомендации в соответствии со стандартами REST/HTTP для включения таких необходимых метаданных в запросы DELETE? Есть ли другие альтернативы, которые я не рассматривал?
5 ответов
Несмотря на некоторые рекомендации не использовать тело сообщения для запросов DELETE, этот подход может быть уместным в определенных случаях использования. Это подход, который мы в конечном итоге использовали после оценки других вариантов, упомянутых в вопросе / ответах, и после сотрудничества с потребителями услуги.
Хотя использование тела сообщения не является идеальным, ни один из других вариантов не был идеально подходящим. Тело запроса DELETE позволило нам легко и четко добавить семантику вокруг дополнительных данных / метаданных, которые были необходимы для сопровождения операции DELETE.
Я все еще был бы открыт для других мыслей и дискуссий, но хотел замкнуть петлю по этому вопросу. Я ценю все мысли и обсуждения на эту тему!
Учитывая сложившуюся ситуацию, я бы выбрал один из следующих подходов:
- Отправка PUT или PATCH: я делаю вывод, что операция удаления является виртуальной по причине необходимости удаления. Поэтому я считаю, что обновление записи с помощью операции PUT/PATCH является допустимым подходом, даже если это не операция DELETE сама по себе.
- Используйте параметры запроса: URI ресурса не изменяется. Я на самом деле думаю, что это тоже правильный подход. Вопрос, который вы связали, говорил о том, что нельзя разрешить удаление, если параметр запроса отсутствует. В вашем случае у меня просто была бы причина по умолчанию, если причина не указана в строке запроса. Ресурс все равно будет
resource/:id
, Вы можете сделать его обнаруживаемым с помощью заголовков ссылок на ресурсе для каждой причины (с помощьюrel
тег на каждом, чтобы определить причину). - Используйте отдельную конечную точку для каждой причины: использование URL-адреса, например
resource/:id/canceled
, Это действительно изменяет Request-URI и определенно не является RESTful. Опять же, заголовки ссылок могут сделать это обнаруживаемым.
Помните, что ОТДЫХ - это не закон или догма. Думайте об этом больше как руководство. Поэтому, когда имеет смысл не следовать указаниям для вашей проблемной области, не делайте этого. Просто убедитесь, что ваши пользователи API проинформированы о разнице.
То, что вы, кажется, хотите, это одна из двух вещей, ни одна из которых не является чистой DELETE
:
- У вас есть две операции,
PUT
причины удаления, сопровождаемойDELETE
ресурса. После удаления содержимое ресурса больше не доступно никому. "Причина" не может содержать гиперссылку на удаленный ресурс. Или же, - Вы пытаетесь изменить ресурс из
state=active
вstate=deleted
используяDELETE
метод. Ресурсы с состоянием = удалено игнорируются вашим основным API, но все же могут быть доступны для чтения администратору или кому-либо, имеющему доступ к базе данных. Это разрешено -DELETE
не нужно стирать резервные данные для ресурса, только для удаления ресурса, выставленного по этому URI.
Любая операция, которая требует тела сообщения на DELETE
запрос может быть разбит на самое общее, POST
выполнить все необходимые задачи с телом сообщения и DELETE
, Я не вижу причин нарушать семантику HTTP.
Я бы сказал, что параметры запроса являются частью определения ресурса, поэтому вы можете использовать их для определения объема вашей операции, а затем «применить» операцию. Мой вывод состоит в том, что параметры запроса , как вы определили, являются лучшим подходом.
Я предлагаю вам включить необходимые метаданные как часть самой иерархии URI. Пример (Наивный):
Если вам нужно удалить записи на основе диапазона дат, вместо того, чтобы передавать начальную и конечную дату в теле или в качестве параметров запроса, структурируйте URI таким образом, чтобы вы передавали необходимую информацию как часть URI.
например
DELETE /entries/range/01012012/31122012
- Удалить все записи в период с 1 января 2012 года по 31 декабря 2012 года.
Надеюсь это поможет.