2013-06-13 2 views
29

Wir alle wissen, die "Standard" Weg zum Löschen eines einzelnen Elements über REST ist eine einzige DELETE-Anfrage an einen URI example.com/Items/666 senden. Großartig, lassen Sie uns fortfahren, viele auf einmal zu löschen. Da wir kein atomares Löschen (oder eine echte Transaktion, dh alles oder nichts) benötigen, könnten wir dem Kunden nur sagen, dass er viel Glück haben und viele Anfragen stellen muss, aber das ist nicht sehr schön. Wir brauchen also einen Weg, um es einem Kunden zu ermöglichen, viele 'Items' gleichzeitig zu löschen.Warum verwenden zwei Schritte Ansatz zum Löschen mehrerer Elemente mit REST

Nach meinem Verständnis ist die "typische" Lösung dieses Problems ein "zweistufiger" Ansatz. Zuerst sendet der Client eine Liste von Element-IDs und erhält einen URI wie example.com/Items/Collection/1. Sobald diese Sammlung erstellt ist, rufen sie DELETE darauf auf.

Nun, ich sehe, dass das funktioniert gut, außer mir, es ist eine schlechte Lösung. Erstens zwingen Sie den Client, zwei Anforderungen an den Server zu stellen. Zweitens: "Ich dachte, dass DELETE ein Element löschen sollte?", Sollte DELETE auf diesem URI nicht effektiv abbrechen (es handelt sich jedoch nicht um eine echte Transaktion), wie würden wir es sogar abbrechen? Wirklich wäre besser, wenn es eine Form "EXECUTE" -Aktion gab, aber ich kann das Boot das viel nicht rocken. Es zwingt den Server auch, zu berücksichtigen, dass der JSON, der POSTed wurde, eher wie eine Anfrage aussieht, um diese Items zu modifizieren, aber die Anfrage war DELETE ... also denke ich, dass ich sie löschen werde. Dieser Ansatz beginnt auch, dem Client/Server eine Art Status aufzuzwingen, nicht ein echter Zustand, den ich zugeben werde, aber es ist eine Art von Zustand.

Meiner Meinung nach wäre eine bessere Lösung, einfach DELETE unter example.com/Items (oder vielleicht example.com/Items/Collection, um zu sagen, dass dies ein mehrfaches Löschen ist) aufzurufen und JSON-Daten mit einer Liste von IDs zu übergeben, die Sie löschen möchten. Soweit ich sehen kann, löst das im Grunde genommen alle Probleme der ersten Methode. Es ist einfacher, als ein Client zu verwenden, reduziert die Arbeit, die der Server zu tun hat, ist wirklich zustandslos, ist semantischer.

Ich würde wirklich die Rückmeldung zu diesem Thema zu schätzen, vermisse ich etwas über REST, die meine Lösung für dieses Problem unrealistisch macht? Ich würde auch Links zu Artikeln schätzen, besonders wenn sie diese beiden Methoden vergleichen. Ich bin mir bewusst, dass dies normalerweise nicht für SO gilt. Ich muss in der Lage sein zu widerlegen, dass nur die erste Methode wirklich RESTful ist, beweisen, dass der zweite Ansatz eine praktikable Lösung ist. Natürlich, wenn ich den falschen Baum belle, sag es mir.

Antwort

24

Ich habe die letzte Woche oder so verbracht, ein bisschen über REST zu lesen, und nach meinem besten Verständnis, wäre es falsch, eine dieser Lösungen als 'RESTfull' zu beschreiben, eher sollten Sie sagen, dass 'keine Lösung geht gegen was REST bedeutet ".

Die kurze Antwort ist einfach, dass REST, wie in Roy Fielding's dissertation (siehe Kapitel 5) dargelegt, nicht das Thema zum Löschen von Ressourcen, singular oder multiple, in einem REST-Manor behandelt. Das stimmt, es gibt keine "richtige RESTful-Methode, um eine Ressource zu löschen" ... naja, nicht ganz.

REST selbst definiert nicht, wie eine Ressource gelöscht wird, aber es definiert, dass jedes Protokoll, das Sie verwenden (denken Sie daran, dass REST kein Protokoll ist), die Ausführung dieser Aktionen diktiert. Das Protokoll wird normalerweise HTTP sein; "Normalerweise" ist das Schlüsselwort als Fielding will point out, REST ist nicht gleichbedeutend mit HTTP.

Also schauen wir auf HTTP um zu sagen, welche Methode 'richtig' ist. Was HTTP betrifft, sind beide Ansätze leider praktikabel. Ja "lebensfähig". HTTP ermöglicht es einem Client, eine POST-Anforderung mit einer Nutzlast zu senden (um eine Auflistungsressource zu erstellen) und dann eine DELETE-Methode für diese neue Auflistung aufzurufen, um die Ressourcen zu löschen. Außerdem können Sie die Daten innerhalb der Nutzlast einer einzelnen DELETE-Methode senden, um die Ressourcenliste zu löschen.HTTP ist einfach das Medium, über das Sie Anfragen an den Server senden, es wäre Aufgabe des Servers, entsprechend zu reagieren. Für mich scheint das HTTP-Protokoll an einigen Stellen ziemlich interpretationsfähig zu sein, aber es scheint ziemlich klare Richtlinien dafür zu geben, welche Aktionen bedeuten, wie sie behandelt werden sollten und welche Reaktion gegeben werden sollte; Es ist nur ein "Du solltest das tun" und nicht "Du musst das tun", aber vielleicht bin ich ein wenig pedantisch in der Formulierung.

Einige Leute würden argumentieren, dass der 'zweistufige' Ansatz unmöglich 'REST' sein kann, da der Server einen 'Status' speichern muss, damit der Client die zweite Aktion ausführen kann. Dies ist einfach ein Missverständnis eines Teils. Es muss verstanden werden, dass weder der Client noch der Server irgendeine "Status" -Information über die andere zwischen der Liste, die POSTIERT wird und dann anschließend DELETED wird, speichert. Ja, die Liste muss erstellt worden sein, bevor sie gelöscht werden kann, aber der Server erinnert sich nicht daran, dass Client Alpha diese Liste erstellt hat (ein solcher Ansatz würde es dem Client erlauben, einfach DELETE als nächste Anfrage aufzurufen und der Server erinnert sich Um diese Liste zu verwenden, wäre dies überhaupt nicht statuslos. Daher muss der Client dem Server mitteilen, dass er diese bestimmte Liste löschen soll, die Liste, für die er eine bestimmte URI erhalten hat. Wenn der Client versucht hat, eine Sammelliste zu löschen, die noch nicht existiert, wird einfach gesagt, dass die Ressource nicht gefunden werden kann (der klassische 404-Fehler ist am wahrscheinlichsten). Wenn Sie behaupten möchten, dass dieser zweistufige Ansatz einen Zustand aufrechterhält, müssen Sie auch behaupten, dass das einfache Abrufen eines URI einen Zustand erfordert, da der URI zuerst existieren muss. Zu behaupten, dass es diesen "Staat" gibt, ist Missverständnis, was "Staat" bedeutet. Und als weiterer "Beweis", dass ein solcher zweistufiger Ansatz in der Tat zustandslos ist, könnte man durchaus Client Alpha POST der Liste und später Client Beta (ohne irgendeine Kommunikation mit dem anderen Client) DELETE auf den Listenressourcen aufrufen.

Ich denke, es kann ziemlich selbstverständlich sein, dass die zweite Option, nur die Liste in der Nutzlast der DELETE-Anfrage zu senden, staatenlos ist. Alle Informationen, die zur Vervollständigung der Anfrage benötigt werden, sind vollständig in der einen Anfrage gespeichert.

Es könnte jedoch argumentiert werden, dass die DELETE-Aktion nur für eine "greifbare" Ressource aufgerufen werden sollte, aber dabei ignorierst du eklatant den REpresentational-Teil von REST; Es ist im Namen! Es ist der gegenständliche Aspekt, der URIs wie "http://example.com/myService/timeNow" erlaubt, ein URI, der bei "erhalten" dynamisch die aktuelle Zeit zurückgibt, ohne dass eine Datei geladen oder aus einer Datenbank gelesen werden muss. Es ist ein Schlüsselkonzept, dass die URIs nicht direkt auf "greifbare" Daten abbilden.

Es gibt jedoch einen Aspekt dieser staatenlosen Natur, der in Frage gestellt werden muss. Als Fielding die ‚Client-stateless-Server‘ in Abschnitt 5.1.3 beschreibt, sagt er:

We next add a constraint to the client-server interaction: communication must 
    be stateless in nature, as in the client-stateless-server (CSS) style of 
    Section 3.4.3 (Figure 5-3), such that each request from client to server must 
    contain all of the information necessary to understand the request, and 
    cannot take advantage of any stored context on the server. Session state is 
    therefore kept entirely on the client. 

Der wichtigste Teil hier in meinen Augen „nehmen kann nicht auf dem Server Vorteil aller gespeicherten Kontext“ ist. Jetzt gebe ich Ihnen zu, dass "Kontext" etwas offen für Interpretationen ist. Aber ich finde es schwierig zu sehen, wie Sie eine Liste speichern könnten (entweder im Speicher oder auf der Festplatte), die verwendet wird, um tatsächlich nützliche Bedeutung zu geben, würde diese "Regel" nicht verletzen. Ohne diesen 'Listenkontext' macht die DELETE-Operation keinen Sinn. Daher kann ich nur zu dem Schluss kommen, dass die Verwendung eines zweistufigen Ansatzes zur Durchführung einer Aktion wie das Löschen mehrerer Ressourcen nicht als "RESTfull" betrachtet werden kann und sollte.

Ich missgönne auch etwas die Mühe, die dafür gemacht werden musste, Argumente dafür zu finden. Das Internet insgesamt scheint von dieser Idee erfasst worden zu sein, der zweistufige Ansatz ist der "RESTfull" -Weg, der solche Aktionen ausführt, mit der Begründung "es ist der RESTvolle Weg, dies zu tun". Wenn Sie einen Moment von dem zurücktreten, was alle anderen tun, werden Sie sehen, dass beide Ansätze die gleiche Liste senden müssen, so dass sie vom Argument ignoriert werden können. Beide Ansätze sind "gegenständlich" und "staatenlos". Der einzige wirkliche Unterschied besteht darin, dass aus irgendeinem Grund ein Ansatz beschlossen hat, zwei Anforderungen zu stellen.Diese beiden Anfragen enthalten dann weitere Fragen, z. B. wie lange diese Daten aufbewahrt werden und wie ein Client einem Server mitteilt, dass er diese Sammlung nicht mehr möchte, aber die tatsächlichen Ressourcen beibehalten möchte, auf die er verweist ".

Also bin ich bis zu einem gewissen Punkt, beantworte meine Frage mit der gleichen Frage: "Warum würdest du überhaupt einen zweistufigen Ansatz in Betracht ziehen?"

+2

Ich denke nicht, dass der Punkt von REST ist, dass der Server ** keinen ** Status haben kann (z. B. Status ist erforderlich, um die IDs in Ihrer Liste zu * etwas * auf dem Server zuzuordnen), aber das Es hat keinen Status * pro Sitzung *. Als solche ist wahrscheinlich jede Methode geeignet, obwohl ich zustimme, dass der einstufige Ansatz wahrscheinlich immer noch vorzuziehen ist. –

+0

Wie kommen Sie zu der Schlussfolgerung, dass der One-Step-Ansatz den Status pro Sitzung enthält? Ich dachte, ich machte deutlich, dass keiner der Ansätze einen Zustand pro Sitzung erfordert, wie es so oft für einen Einkaufswagen verwendet wird. – thecoshman

+0

Ich bin zu keiner solchen Schlussfolgerung gekommen - ich bin einfach zu dem Schluss gekommen, dass der "Staat", der an dem zweistufigen Ansatz beteiligt ist, nicht (notwendigerweise) die REST-Ideen verletzt. –

2

IMO:

HTTP DELETE auf bestehende Sammlung all seiner Mitglieds zu löschen scheint in Ordnung. Erstellen Sie die Sammlung, nur um alle Mitglied klingt ungerade zu löschen. Wie Sie selbst vorschlagen, übergeben Sie einfach die IDs der zu löschenden Elemente mit JSON (oder einem anderen Nutzlastformat). Ich denke, dass der Server versuchen sollte, mehrere Löschungen eine interne Transaktion zu machen.

+0

Soweit Sie wissen, ist ihr * technischer * Grund, warum Sie eine Nutzlast im Rumpf einer DELETE-Anfrage nicht so senden können? Von dem, was ich über die HTTP-Spezifikation gelesen habe; Alle Request-Methoden können, sofern nicht anders angegeben, einen Nachrichtentext haben, und die DELETE-Anfrage sagt nichts anderes. Obwohl, um nit pickers zu re-empty, ja, es ist eine 'Entität' – thecoshman

+0

Ich kenne kein Problem mit Nutzlast in DELETE. Wir haben es sowohl in DELETE als auch in GET (do not ask) Methoden verwendet. – wilx

+0

(das macht eigentlich Sinn). Sehen Sie, ich werde mich mit einer Schnittstelle befassen, an die Massenaktionen gesendet werden sollen; Hunderte von Erstellungen, Löschungen und Aktualisierungen auf einmal. Dies ist auf interne Mechanismen zurückzuführen, was bedeutet, dass wir schneller verarbeiten können, als nacheinander zu empfangen. Neugierig, wie würdest * du * das erreichen? Kennen Sie Ressourcen, die diese beiden Ansätze diskutieren? Für mich erscheint es ziemlich einfach, eine Signalanfrage ist einfacher zu bedienen und erspart dem Server die Sorge, wie lange er diese Listen behalten soll. – thecoshman

1

Ich würde argumentieren, dass HTTP bereits bietet eine Methode zum Löschen mehrerer Elemente in Form von persistent connections and pipelining. Auf der HTTP-Protokoll-Ebene ist es absolut in Ordnung, idempotente Methoden wie DELETE auf Pipeline-Art anzufordern - das heißt, alle DELETE-Anfragen gleichzeitig auf einer einzigen Verbindung zu senden und auf alle Antworten zu warten.

Dies kann für einen AJAX-Client, der in einem Browser ausgeführt wird, problematisch sein, da einige Browser die Unterstützung für das Pipelining standardmäßig aktiviert haben. Dies ist nicht die Schuld von HTTP, aber es ist die Schuld dieser spezifischen Clients.

+0

Das sind effektiv mehrere einzelne Löschanforderungen, die über eine 'persistente' Pipe ausgeführt werden. Es ist also nur eine (und nicht so schlechte) Arbeit, die Tatsache zu verarbeiten, dass HTTP grundsätzlich auf einer Ressource pro Anfrage arbeitet. – thecoshman

Verwandte Themen