Можно ли частично изменить коллекцию с помощью PUT или DELETE?

21

У меня есть коллекция продуктов в группе продуктов, например:

product-groups/123/products
  1. Если мне нужно добавить в коллекцию, это нормально, что я пропускаю только некоторые продукты с PUT?

  2. Если мне нужно удалить некоторые товары из коллекции, можно ли передать данные фильтра (массив идентификаторов) с помощью команды DELETE?

Какой лучший способ реализовать функциональность в духе ReST?

Изменить: элементы являются ссылками на отдельные объекты, в основном идентификаторы продуктов.

user151851
источник
Управляются ли пункты в группе продуктов отдельными ресурсами в другом месте? Или они являются только частью коллекции группы продуктов? Могут ли продукты, если они разделены, принадлежать нескольким группам продуктов?
Мартин Питерс
2
Возможно PATCH В этой спецификации определяется новый метод HTTP / 1.1 [RFC2616], PATCH, который используется для применения частичных модификаций к ресурсу.
Esailija
Продукт (ID) может принадлежать нескольким группам продуктов.
user151851
Есть ли хорошо известный способ (лучшая практика), чтобы сказать, как ПАТЧИРОВАТЬ, то есть добавить или удалить продукты в коллекции?
user151851
Аналогичный вопрос на SO stackoverflow.com/questions/411462/…
Люк Пуплетт

Ответы:

10

В общем, у вас есть одна конечная точка, которая представляет всю коллекцию x :

/products

Скажем, вы хотите обновить один продукт, вы делаете PUT для /products/{id}. Если вы хотите частично обновить отдельный продукт (не обновляя каждое поле), вы также можете использовать PATCH для /products/{id}. То же самое касается удаления одного объекта ( УДАЛИТЬ в /products/{id}).

Если вы хотите настроить таргетинг на одного Ressource, вы имеете право по пути, который сингл Ressource, вы хотите изменить.

Единственное действие, которое нарушает схему, - это создание ресурса. При создании ресурса вы нацеливаетесь на коллекцию в целом, говорите POST для /products.

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

Например, вы хотите получить подмножество продуктов красного цвета, вы запрашиваете его

GET к /products?colour=red.

Итак, если вы хотите удалить все это, вы УДАЛИТЕ /products?colour=red . Или , если вы хотите удалить некоторые из продуктов через id, можно УДАЛИТЬ /products?id=1&id=2&id=3 .

Как насчет массового создания ресурсов? Разместите свою коллекцию [{...},{...},{...}]просто в /products. То же самое касается PUT и PATCH .

Это действительно просто.

Чтобы ответить на ваши вопросы:

Если мне нужно добавить в коллекцию, это нормально, что я пропускаю только некоторые продукты с PUT?

Это не только хорошо, вам рекомендуется делать это так.

Если мне нужно удалить некоторые товары из коллекции, можно ли передать данные фильтра (массив идентификаторов) с помощью команды DELETE?

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

Томас Джанк
источник
2
PUT - операция замены. Вызов PUT для конечной точки сбора с «некоторыми продуктами» должен удалить (в случае ОП удалить отношение к) любой продукт, который не включен в список «некоторых продуктов». Хотя он может использоваться для добавления предметов, он также должен удалять предметы, которые не являются (на мой взгляд) тем, что ожидает ОП. Вы должны пересмотреть свой ответ на их первый вопрос соответственно.
Клейтонд
@claytond: Полагаю, что с ответом все в порядке, пока выполняется частичное обновление PATCHи полная замена через PUT.
9000
4
@ 9000. Конечно, но в настоящее время ответ гласит: «Вам предлагается ... добавить в коллекцию ... [путем] пропуска [только] некоторые продукты с PUT». Это, конечно, неправильно. Рекомендуется POST. Умеет ставить ... но только передавая все (не некоторые) предметы.
Клейтонд
5

Обычно методы REST предназначены для работы с одним объектом / объектом (CRUD).

Есть несколько вариантов:

  • Рассматривайте свои коллекции как сущности и обновляйте их через POST
  • Создание альтернативных операций без REST

Первый соответствует стандартам REST, но может быть дорогостоящим, так как ваши объекты / объекты коллекции могут быть очень большими (обновление группы, состоящей из тысяч продуктов только для добавления / удаления одного продукта, было бы тяжелым запросом).

Второй вариант предпочтителен многими API как способ расширить REST за пределы операций CRUD.

Например:

GET product-groups/123/products (list all the products in the group)
POST product-groups/123/products/append (POST a list of new product ids to append to the group)
POST product-groups/123/products/remove (POST a list of product ids to remove from the group)

Многие API всегда используют POST для этих расширенных операций, но ничто не ограничивает вас в использовании других методов http (кроме ограничения GET и DELETE, чтобы иметь пустое тело)

Энеко Алонсо
источник
Конечно, есть несколько способов достичь цели. Какой из них является лучшей практикой? Какой из них будет более перспективным?
user151851
4
@ user151851: Полное соответствие REST (если оно есть) - высокая цель. Схема подхода здесь кажется более реалистичной, поскольку он пытается использовать подход, который фактически используется в «реальном мире», что делает его, по сути, де-факто-стандартом. Это примерно как будущее, как вы собираетесь получить.
Роберт Харви
2
Разве мы не вводим пользовательские глаголы, используя «добавление» и «удаление» в URL? Таким образом, мы должны будем объяснить, как использовать API. Разве мы не должны повторно использовать то, что у нас есть, т.е. методы HTTP? В этом случае действия хорошо известны.
user151851
7
Для всех, кто попадает в этот ответ: это неправильно. Как упомянуто @ user151851, это вводит глаголы в URL, который почти не RESTful, как вы можете получить. Что касается самого вопроса, у меня нет хорошего ответа, но это не так.
Umbrae
Может ли «расширение» быть более ориентированным на ресурсы, делая его так, чтобы оно products/collectionвозвращало «конверт» предметов и содержимое конверта, измененное через PUT? Например, «вот как я хочу, чтобы элементы в коллекции были».
Люк Пуплетт
3

Просто чтобы уточнить предыдущие ответы / комментарии.

Насколько мне известно, POST является методом добавления отдельных элементов в коллекцию.

DELETE, в свою очередь, это метод удаления отдельного элемента из коллекции. Оба сценария отлично подходят.

Однако вы должны использовать соответствующий URI для ссылки на отдельный элемент или всю коллекцию.

Например, чтобы добавить элемент в коллекцию, вы должны отправить данные в следующий URI:

https://www.factory.net/products/

Чтобы удалить один продукт из коллекции, вы можете использовать метод DELETE, отправляющий запрос на что-то вроде:

https://www.factory.net/products/108/

Метод PATCH можно использовать для обновления некоторых элементов в коллекции. Например, когда вам нужно обновить только одно поле в одном элементе. Оформление полного представления ресурса для очень большой коллекции может быть очень дорогостоящей операцией.

Лукаш
источник
2

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

  • PUT - полная замена.

    • Если вы кладете на одиночный файл (например /item/{id}) и пропускаете nameего, его следует очистить или установить на ноль или что-то подобное.
    • Если вы кладете в коллекцию и не включаете элемент, он должен быть удален из этой коллекции.

    Хотя PUT может использоваться для добавления предметов, вы должны отправить «все» предметы. Отправка «некоторых» предметов должна привести к удалению (я полагаю, что это не то, чего желает ОП).

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

  • PATCH также действителен. Теоретически, вы должны предоставить список «операций». Например, технически вы должны отправить что-то вроде:

    [{ 
        "action": "update",
        "id": <id>,
        "value": {...}
    },{
        "action": "add",
        "value": {...}
    }, ...]
    

    На практике чаще встречается API, который принимает частичный список объектов, каждый элемент которого обрабатывается с использованием логики UPSERT (обновление или вставка).

  • Технически, POST должен обрабатывать ввод «в соответствии с собственной специфической семантикой ресурса».

    • На практике POST обычно используется для операций создания.
    • Однако POST также является глаголом, используемым для нестандартных вызовов. В то время как ведутся активные дискуссии о том, являются ли конечные точки действий строго RESTful (я согласен с «нет»), POST - подходящий глагол, если вы отправляете запрос в конечную точку, подобную {resource}/activate.

ПРИМЕЧАНИЕ. При использовании операций не-GET для коллекций тщательно продумайте определение успеха и неудачи. ОТДЫХ не дает хорошего способа сообщить о частичном успехе. Хорошим значением по умолчанию является допущение, что вы будете запускать операцию в транзакции с критерием успеха "все или ничего". Если это не то, что вам нужно, вы, вероятно, не должны напрямую взаимодействовать с коллекцией.

claytond
источник