Ist es in Ordnung, eine Sammlung mit PUT oder DELETE teilweise zu ändern?

21

Ich habe eine Sammlung von Produkten in einer Produktgruppe, zB:

product-groups/123/products
  1. Wenn ich der Sammlung hinzufügen muss , ist es in Ordnung, dass ich nur einige Produkte mit PUT übergebe?

  2. Wenn ich einige Produkte aus der Sammlung löschen muss , ist es in Ordnung, dass ich Filterdaten (ein Array von IDs) mit DELETE übergebe?

Wie lässt sich die Funktionalität im Sinne von ReST am besten umsetzen?

Bearbeiten: Die Elemente sind Links zu separaten Entitäten, im Grunde IDs von Produkten.

user151851
quelle
Werden die Artikel in der Produktgruppe separat verwaltet? Oder sind sie nur ein Teil der Produktgruppensammlung? Wenn getrennt, können Produkte mehreren Produktgruppen angehören?
Martijn Pieters
2
Vielleicht PATCH In dieser Spezifikation wird die neue HTTP / 1.1-Methode [RFC2616] PATCH definiert, mit der teilweise Änderungen an einer Ressource vorgenommen werden.
Esailija
Ein Produkt (ID) kann mehreren Produktgruppen angehören.
user151851
Gibt es eine bekannte Methode (Best Practice) zum PATCHEN, dh Hinzufügen oder Löschen von Produkten in der Sammlung?
user151851
Ähnliche Frage auf SO stackoverflow.com/questions/411462/…
Luke Puplett

Antworten:

10

Im Allgemeinen haben Sie einen Endpunkt, der die gesamte Sammlung von x darstellt :

/products

Sag mal, wollen Sie ein einzelnes Produkt zu aktualisieren, Sie machen PUT zu /products/{id}. Wenn Sie ein einzelnes Produkt teilweise aktualisieren möchten (nicht jedes Feld aktualisieren), können Sie auch einen PATCH to verwenden /products/{id}. Gleiches gilt für das Löschen einer einzelnen Entität ( DELETE to /products/{id}).

Wenn Sie auf eine einzelne Ressource abzielen möchten , qualifizieren Sie sich über den Pfad, welche einzelne Ressource Sie ändern möchten.

Die einzige Aktion, die das Schema bricht, ist die Erstellung einer Ressource. Wenn Sie eine Ressource erstellen, zielen Sie auf die gesamte Sammlung ab, sagen Sie POST zu /products.

Es sollte jedoch klar sein, dass das Ziel für Operationen, die die gesamte Sammlung betreffen, zum entsprechenden Sammlungsendpunkt gehen sollte.

Wenn Sie beispielsweise eine Untergruppe roter Produkte abrufen möchten, fragen Sie nach

GET to /products?colour=red.

Also, wenn Sie alle diese löschen möchten, Sie DELETE /products?colour=red . Oder wenn Sie einige Produkte über löschen möchten id, können Sie LÖSCHEN /products?id=1&id=2&id=3 .

Was ist bulk Schaffung von Ressourcen? POST Ihre Sammlung [{...},{...},{...}]einfach an /products. Gleiches gilt für PUT und PATCH .

Das ist wirklich unkompliziert.

Um Ihre Fragen zu beantworten:

Wenn ich der Sammlung hinzufügen muss, ist es in Ordnung, dass ich nur einige Produkte mit PUT übergebe?

Es ist nicht nur in Ordnung, Sie werden auch dazu ermutigt.

Wenn ich einige Produkte aus der Sammlung löschen muss, ist es in Ordnung, dass ich Filterdaten (ein Array von IDs) mit DELETE übergebe?

Das ist in Ordnung. Wie Eneko Alonso schrieb, gibt es manchmal Massenoperationen , die über "Controller" -Endpunkte gekapselt sind , dh ein POST wird verwendet, um (komplexe) Operationen auszulösen.

Thomas Junk
quelle
2
PUT ist eine Ersetzungsoperation. Das Aufrufen von PUT auf einem Sammlungsendpunkt mit "einigen Produkten" sollte alle Produkte löschen (im Fall des OP die Beziehung zu löschen), die nicht in der Liste "einiger Produkte" enthalten sind. Es könnte zwar zum Hinzufügen von Elementen verwendet werden, sollte jedoch auch Elemente entfernen, die (meiner Meinung nach) nicht den Erwartungen des OP entsprechen. Sie sollten Ihre Antwort auf die erste Frage entsprechend überarbeiten.
Claytond
@claytond: Ich nehme an, die Antwort ist in Ordnung, solange ein teilweises Update mit PATCHund ein vollständiger Austausch über erfolgt PUT.
9000
4
@ 9000. Natürlich, aber die Antwort lautet derzeit "Sie werden ermutigt, ... nur einige Produkte mit PUT zu [umgehen] ... der Sammlung hinzuzufügen". Das ist sicher falsch. Zum POST ermutigt. PUT-fähig ... aber nur durch Übergeben aller (nicht einiger) Elemente.
Claytond
5

Normalerweise sollen REST-Methoden auf einer einzelnen Entität / einem einzelnen Objekt (CRUD) ausgeführt werden.

Es gibt verschiedene Möglichkeiten:

  • Behandeln Sie Ihre Sammlungen als Entitäten und aktualisieren Sie sie über POST
  • Erstellen Sie alternative Nicht-REST-Operationen

Der erste folgt den REST-Standards, kann jedoch teuer sein, da Ihre Sammlungsobjekte / -entitäten sehr groß sein können (die Aktualisierung einer Gruppe mit Tausenden von Produkten, um nur ein Produkt hinzuzufügen / zu entfernen, wäre eine große Anforderung).

Die zweite Option wird von vielen APIs bevorzugt, um REST über die CRUD-Operationen hinaus zu erweitern.

Beispielsweise:

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)

Viele APIs verwenden immer POST für diese erweiterten Operationen, aber nichts beschränkt Sie auf die Verwendung anderer http-Methoden (außer der Beschränkung von GET und DELETE, um einen leeren Textkörper zu haben).

Eneko Alonso
quelle
Sicher, es gibt ein paar Methoden, um das Ziel zu erreichen. Welches ist die beste Praxis? Welches ist zukunftssicherer?
user151851
4
@ user151851: Vollständige REST-Konformität (wenn es so etwas gibt) ist ein hohes Ziel. Der hier skizzierte Ansatz erscheint insofern realistischer, als er versucht, einen Ansatz zu verwenden, der tatsächlich in der "realen Welt" verwendet wird, was ihn im Wesentlichen zu einem Defacto-Standard macht. Das ist ungefähr so ​​zukunftssicher, wie es nur geht.
Robert Harvey
2
Führen wir keine benutzerdefinierten Verben mit "Anhängen" und "Löschen" in der URL ein? Auf diese Weise müssen wir erklären, wie die API verwendet wird. Sollten wir nicht das, was wir haben, wiederverwenden, dh die HTTP-Methoden? In diesem Fall sind die Aktionen bekannt.
user151851
7
Für alle anderen, denen diese Antwort einfällt: Es ist falsch. Wie @ user151851 erwähnt, werden hierdurch Verben in die URL eingefügt, die so wenig wie möglich REST-konform sind. In Bezug auf die eigentliche Frage habe ich keine gute Antwort, aber diese ist es nicht.
Umbrae
Könnte die "Erweiterung" ressourcenorientierter sein, indem sie products/collectioneinen "Umschlag" von Elementen zurückgibt und den Umschlaginhalt über einen PUT ändert? Zum Beispiel: "Genau so möchte ich die Artikel in der Sammlung haben".
Luke Puplett
3

Nur um vorherige Antworten / Kommentare zu präzisieren.

Nach meinem Wissen ist POST die Methode, um der Sammlung einzelne Elemente hinzuzufügen.

DELETE wiederum ist die Methode zum Löschen eines einzelnen Elements aus der Auflistung. Beide Szenarien sind vollkommen RUHIG.

Sie sollten jedoch den entsprechenden URI verwenden, um auf ein einzelnes Element oder die gesamte Auflistung zu verweisen.

Um beispielsweise ein Element zur Auflistung hinzuzufügen, sollten Sie die Daten in den folgenden URI POSTEN:

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

Um ein einzelnes Produkt aus der Sammlung zu löschen, können Sie die DELETE-Methode verwenden, um eine Anfrage an Folgendes zu senden:

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

Mit der PATCH-Methode können einige Elemente in der Auflistung aktualisiert werden. Zum Beispiel, wenn Sie nur ein Feld in einem Element aktualisieren müssen. Das Erstellen einer vollständigen Ressourcendarstellung für eine sehr große Sammlung kann sehr kostspielig sein.

Lukasz
quelle
2

Grundsätzlich sind alle RESTful-Operationen für eine Sammlung gültig, aber stellen Sie sicher, dass Sie verstehen, wie die Semantik der Verben für eine Sammlung gilt:

  • PUT ist ein vollständiger Ersatz.

    • Wenn Sie zu einem Singleton PUT (zB /item/{id}) und weglassen name, sollte es gelöscht oder auf null oder etwas ähnliches gesetzt werden.
    • Wenn Sie zu einer Sammlung zu setzen , und nicht ein Element enthalten, soll es werden entfernt aus dieser Sammlung.

    Während ein PUT zum Hinzufügen von Elementen verwendet werden kann, müssen Sie "alle" Elemente senden. Das Senden "einiger" Elemente sollte zu Entfernungen führen (ich gehe davon aus, dass dies nicht das ist, was das OP wünscht).

  • DELETE ist intuitiver. Es ist gültig, die Sammlung oder eine gefilterte Teilmenge davon zu löschen. Nur die im Filter enthaltenen Elemente sollten betroffen sein.

  • PATCH ist ebenfalls gültig. Theoretisch sollten Sie eine Liste von "Operationen" bereitstellen. Beispielsweise sollten Sie technisch etwas senden wie:

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

    In der Praxis ist es üblicher, eine API zu sehen, die eine Teilliste von Objekten akzeptiert, bei denen jedes Element unter Verwendung einer UPSERT-Logik (Aktualisieren oder Einfügen) verarbeitet wird.

  • Technisch sollte der POST die Eingabe "gemäß der spezifischen Semantik der Ressource" verarbeiten.

    • In der Praxis wird POST normalerweise für "Erstellungs" -Operationen verwendet.
    • POST ist jedoch auch das Verb für nicht standardmäßige Anrufe. Während heftig darüber diskutiert wird, ob Aktionsendpunkte streng REST-konform sind (ich stehe auf der Seite mit den "Nein"), ist POST das geeignete Verb, wenn Sie eine Anfrage an einen Endpunkt wie senden {resource}/activate.

ANMERKUNG: Wenn Sie Non-GET-Vorgänge für Auflistungen verwenden, sollten Sie die Definition von Erfolg und Misserfolg sorgfältig berücksichtigen. Mit REST können Sie keinen guten Teilerfolg kommunizieren. Ein guter Standardwert ist die Annahme, dass Sie den Vorgang in einer Transaktion mit einem Erfolgskriterium ausführen, das alles oder nichts enthält. Wenn Sie dies nicht möchten, sollten Sie wahrscheinlich nicht direkt mit der Sammlung interagieren.

Claytond
quelle