ОТДЫХ - PullRequest
       27

ОТДЫХ

52 голосов
/ 24 декабря 2011

Это довольно распространенное требование для поддержки удаленных или отложенных / пакетных удалений для служб данных. Что мне интересно, так это как реализовать это RESTful способом. Я разрываюсь между несколькими различными вариантами (ни один из которых не кажется мне ужасно привлекательным). Я полагаю, что для этих различных опций характерна необходимость в API, который возвращает все ресурсы, помеченные как удаленные, для определенного типа ресурса.

Вот некоторые варианты, о которых я думал, и некоторые их плюсы и минусы:

Параметры для пометки ресурса как удаленного:

  • Используйте HTTP DELETE, чтобы пометить ресурс как удаленный.
  • Используйте HTTP PUT / POST для обновления удаленного флага. Это не правильно, поскольку отображает то, что по сути является удалением, из метода HTTP DELETE в другие методы HTTP.

Опции, когда GET-ин ресурс помечен для удаления:

  • Возвращает статус HTTP 404 для ресурса, помеченного как удаленный. Чисто и прозрачно, но как мы можем отличить действительно удаленный ресурс от ресурса, помеченного как удаленный.
  • Возврат HTTP-статуса 410. Предоставляет способ узнать разницу, но технически 410 говорит, что «ожидается, что она будет считаться постоянной. Клиентам с возможностями редактирования ссылок СЛЕДУЕТ удалять ссылки на Request-URI после одобрения пользователя». Здесь может быть достаточно места для маневра в словах «ожидаемый» и «ДОЛЖЕН». Не уверен, насколько хорошо 410 поддерживается / понимается там в клиентах.
  • Возвращает HTTP Status 200 и включает поле флага, указывающее, что ресурс удален. Это кажется странным, так как идея его удаления была в первую очередь потому, что вы на самом деле хотели, чтобы он не появлялся. Это возлагает ответственность за фильтрацию удаленных ресурсов на клиентов.

Параметры ответов, которые включают этот удаленный ресурс:

  • Пропустить ресурсы, которые считаются удаленными. Чистый и простой. Но что, если вы действительно хотите знать об удаленных ресурсах.
  • Включите их вместе с полем, указывающим, что они удалены. Это возлагает ответственность за фильтрацию удаленных ресурсов на клиентов. Это затрудняет разбиение на страницы, если вы хотите просматривать страницы только через активные или удаленные ресурсы.

Параметры при обновлении ресурса, помеченного для удаления:

  • Использовать HTTP Status 404. Ресурс ушел, верно? Но как определить разницу между ресурсом, помеченным как удаленный, и ресурсом, фактически удаленным? Тело HTTP в ответе 404 может привести к устранению неоднозначности, но тогда у клиентов останется разбор / интерпретация вашего тела для устранения неоднозначности. Может быть, здесь поможет заголовок ответа? Который из? Пользовательский заголовок?
  • Использовать HTTP Status 409 с сообщением о том, как ресурс должен быть сначала восстановлен.

Варианты восстановления ресурса, помеченного для удаления:

  • Используйте HTTP PUT / POST для операции обновления ресурса и снова отметьте его как активный. Это работает только до тех пор, пока вы не возвращаете HTTP 404 для операции GET для ресурса, поскольку с тех пор он не делает PUT / POST для ресурса, который «не найден» (404).
  • Использовать HTTP PUT / POST для операции создания ресурса. Проблема в том, какие данные имеют приоритет? Данные отправлены в операции создания? Или данные, которые удаляются? отфильтруйте это от любых других запросов, которые возвратили бы это. Затем обработайте HTTP PUT / POST, который создает ресурс как отмененный, если идентификатор ресурса указывает на ресурс, помеченный как удаленный.
  • Отдельный путь REST, выделенный для восстановленных ресурсов, помеченных для удаления.

Это далеко не полный список. Я просто хотел перечислить некоторые варианты, которые прыгали в моей голове.

Я знаю ответ, как это сделать, как обычно, "это зависит". Меня интересует, какие квалификации / требования вы бы использовали для принятия решения? Как вы видели, как это реализовано или реализовано самостоятельно?

Ответы [ 6 ]

8 голосов
/ 24 декабря 2011

По книге: RFC 2616-9,7 :

  The DELETE method requests that the origin server delete the resource 
  identified by the Request-URI. This method MAY be overridden by human 
  intervention (or other means) on the origin server. The client cannot
  be guaranteed that the operation has been carried out, even if the 
  status code returned from the origin server indicates that the action
  has  been completed successfully. However, the server SHOULD NOT 
  indicate success unless, at the time the response is given, if it intends
  to delete the resource or move it to an inaccessible location.

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

  A successful response SHOULD be 200 (OK) if the response includes an entity
  describing the status, 202 (Accepted) if the action has not yet been enacted,
  or 204 (No Content) if the action has been enacted but the response does not
  include an entity.

Если операция задерживается, отправьте 202 и тело объекта, описывающее результат действия. (Подумайте об опрашиваемой «задаче», представляющей отложенное удаление ресурса сервером; теоретически он может навсегда оставить его в этом состоянии.) Все, что ему нужно сделать, - это помешать клиенту снова получить его в исходном виде. . Используйте 410 для кода ответа, а когда «задача» завершится или сервер иным образом удалит ресурс, верните 404.

Однако, если семантика DELETE не имеет смысла для рассматриваемого ресурса, возможно, вы ищете не удаление, а переход состояния дополнения, который изменяет состояние ресурса, но сохраняет его доступным? В этом случае используйте PUT / PATCH, чтобы обновить ресурс и все готово.

4 голосов
/ 24 декабря 2011

Я думаю, что наиболее RESTful способ решить это - использовать HTTP PUT, чтобы пометить ресурс для удаления (и восстановить), а затем использовать HTTP DELETE, чтобы окончательно удалить ресурс. Чтобы получить список ресурсов, помеченных для удаления, я бы использовал параметр в запросе HTTP GET, например. ?state=markedForDeletion. Если вы запрашиваете ресурс, помеченный для удаления без параметра, я думаю, вам следует вернуть статус «404 Not Found».

3 голосов
/ 28 сентября 2017

Краткая версия

Нельзя RESTful восстановить ресурс, используя любой метод на его исходном URI - это нелогично, поскольку любая попытка операции с удаленным ресурсом должна возвращать либо404 или 410. Хотя это явно не указано в спецификации, это явно подразумевается в определении метода DELETE 1 (выделение добавлено):

По сути, этоМетод аналогичен команде rm в UNIX: он выражает операцию удаления на отображении URI исходного сервера, а не ожидание удаления ранее связанной информации.

Другими словами, когда вы УДАЛЯЕТЕ ресурс, сервер больше не отображает этот URI на эти данные.Таким образом, вы не можете PUT или POST сделать это, например, «пометить это как удаленное» и т. Д. (Помните, что ресурс определяется как отображение между URI и некоторыми базовыми данными).

Некоторые решения

Поскольку явно указывается, что базовые данные не обязательно удаляются, это не исключает того, что сервер создает отображение URI new как часть реализации DELETE,тем самым эффективно создавая резервную копию, которую можно восстановить позже.

У вас может быть коллекция "/ Удаленный /", которая содержит все удаленные элементы - но как бы вы на самом деле выполняли восстановление?Пожалуй, самый простой способ RESTful - это заставить клиента получить элемент с помощью GET, а затем отправить его по желаемому URL-адресу.

Что делать, если вам нужно восстановить удаленный элемент в его исходное местоположение?Если вы используете тип мультимедиа, который поддерживает его, вы можете включить исходный URI в ответ на GET из / удаленного / коллекции.Затем клиент может использовать его для POST.Такой ответ может выглядеть следующим образом в JSON:

{
    "original-url":"/some/place/this/was/deleted/from",
    "body":<base64 encoded body>
}

Затем клиент может отправить это тело в этот URI для выполнения восстановления.

В качестве альтернативы, если ваше определение ресурса допускает концепцию перемещения (путем обновления свойства «location» или чего-то в этом роде), вы можете выполнить частичное обновление и избежать обхода всего объекта.Или сделайте то, что делает большинство людей, и внедрите RPC-подобную операцию, чтобы заставить сервер перемещать ресурс!UnRESTful, да, но, вероятно, будет работать нормально в большинстве ситуаций.

Как вы решаете эти вещи

Относительно вопроса о том, как вы решаете эти вещи: вы должны рассмотреть, что означает удаление в контексте вашего приложения, и почему выхочу это.Во многих приложениях ничего не удаляется, и «удалить» на самом деле означает «исключить этот элемент из всех дальнейших запросов / списков и т. Д., Если я явно не удаляю его».Так что на самом деле это просто часть метаданных или операция перемещения.В таком случае зачем использовать HTTP DELETE?Одной из причин может быть, если вы хотите 2-уровневое удаление - мягкую или временную версию, которую нельзя отменить, и жесткую / постоянную версию, которая, ну ... нет.

В отсутствие какого-либо конкретного контекста приложения, я был бы склонен реализовать их следующим образом:

Я не хочу больше видеть этот ресурс, для моего удобства : POST частичное обновление, чтобы пометить ресурс как «временно удаленный»

Я не хочу, чтобы кто-либо мог больше иметь доступ к этому ресурсу, потому что он смущает / обвиняет /стоит мне денег / и т. д. : HTTP DELETE

Следующий вопрос, который следует рассмотреть, заключается в следующем: следует ли при постоянном удалении только постоянное удаление URI, чтобы никто больше не мог ссылаться на него, или необходимо также удалить исходные данные?Очевидно, что если вы сохраните данные, то администратор сможет восстановить даже «навсегда» удаленный ресурс (однако не через какой-либо интерфейс RESTful).Недостатком этого является то, что если владелец данных действительно хочет его очистить, то администратор должен сделать это вне интерфейса REST.

2 голосов
/ 24 января 2018

«Удаленные» (уничтоженные) элементы также могут рассматриваться как ресурс, верно?Затем мы можем получить доступ к этому ресурсу одним из следующих способов (например, для удаленного пользователя):

PATCH deleted_users/{id}
PATCH trash/users/{id}
PATCH deleted/users/{id}

или некоторые люди могут подумать, что это более спокойный способ:

PATCH deleted/{id}?type=users

ив полезной нагрузке идет что-то вроде этого:

{ deleted_at: null }
1 голос
/ 03 декабря 2018

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

Другие правы, что DELETE - это путь. Вы можете включить флаг, чтобы определить, является ли это немедленно перманентом DELETE или перемещением в корзину (и, вероятно, только администраторы могут сделать немедленный перманент DELETE.)

DELETE /api/1/book/33
DELETE /api/1/book/33?permanent

Затем сервер может пометить книгу как удаленную. Предполагая, что у вас есть база данных SQL, это может быть что-то вроде:

UPDATE books SET status = 'deleted' WHERE book_id = 33;

Как уже упоминалось другими, как только DELETE сделано, GET коллекции не возвращает этот элемент. С точки зрения SQL это означает, что вы должны убедиться, что не вернули элемент со статусом deleted.

SELECT * FROM books WHERE status <> 'deleted';

Кроме того, когда вы делаете GET /api/1/book/33, вы должны вернуть 404 или 410. Одна из проблем с 410 состоит в том, что это означает, что ушел Навсегда (по крайней мере, это мое понимание этого кода ошибки), так Я бы возвратил 404, если элемент существует , но помечен как 'deleted' и 410 после его окончательного удаления.

Теперь, чтобы восстановить, правильный путь - PATCH. В отличие от PUT, который используется для обновления элемента, ожидается, что PATCH будет операцией с элементом. Из того, что я вижу, ожидается, что операция будет в полезной нагрузке. Чтобы это работало, ресурс должен быть доступен каким-то образом. Как предложил кто-то другой, вы можете указать область trashcan, в которой книга появится после удаления. Примерно так будет работать для перечисления книг, которые были помещены в мусорную корзину:

GET /api/1/trashcan/books

[{"path":"/api/1/trashcan/books/33"}]

Итак, итоговый список теперь будет включать книгу № 33, которую затем вы можете PATCH выполнить с помощью такой операции:

PATCH /api/1/trashcan/books/33

{
    "operation": "undelete"
}

Если вы хотите сделать операцию более универсальной, вы можете использовать что-то вроде:

PATCH /api/1/trashcan/books/33

{
    "operation": "move",
    "new-path": "/api/1/books/33"
}

Тогда «перемещение» может быть использовано для других изменений URL, где это возможно в вашем интерфейсе. (Я работаю над CMS, где путь к странице находится в одной таблице с именем tree, а каждая страница находится в другой таблице с именем page и имеет идентификатор. Я могу изменить путь страницы, перемещая ее между пути в моей таблице tree! Здесь очень полезен PATCH.

К сожалению, RFC не дают четкого определения PATCH, только то, что он должен использоваться с операцией, как показано выше, в отличие от PUT, который принимает полезную нагрузку, представляющую новую версию, возможно частичную, целевой элемент:

PUT /api/1/books/33

{
    "title": "New Title Here"
}

Принимая во внимание, что PATCH (если бы вы поддерживали оба) было бы:

PATCH /api/1/books/33

{
    "operation": "replace",
    "field": "title",
    "value": "New Title Here"
}

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

Вы можете думать об этом как: использовать патч, чтобы изменить виртуальное поле или выполнить сложную операцию, такую ​​как перемещение, которое в противном случае потребовало бы GET, POST, DELETE ( и это при условии, что DELETE является немедленным, и вы можете получить ошибки и получить частичное перемещение ...) В некотором смысле, PATCH похоже на использование любого количества методов. Метод UNDELETE или MOVE будет работать аналогичным образом, но в RFC четко сказано, что существует набор стандартизированных методов , и вам непременно следует придерживаться их, а PATCH дает вам множество комната, чтобы не пришлось добавлять свои собственные методы. Хотя в спецификациях я ничего не видел, говоря, что вы не должны добавлять свои собственные методы. Если вы это сделаете, убедитесь, что четко документировали их.

0 голосов
/ 04 июня 2019

Мы заставили модель создать

POST / имя модели /: id / undelete

...