it-swarm.com.de

REST API - PUT vs PATCH mit Beispielen aus der Praxis

Zunächst einige Definitionen:

PUT ist in Abschnitt 9.6 RFC 2616 definiert:

Die PUT-Methode fordert an, dass die eingeschlossene Entität unter dem angegebenen Request-URI gespeichert wird. Wenn sich der Anforderungs-URI auf eine bereits vorhandene Ressource bezieht, MUSS die beigefügte Entität als eine modifizierte Version der auf dem Origin-Server befindlichen Entität betrachtet werden. Wenn der Anforderungs-URI nicht auf eine vorhandene Ressource verweist und dieser URI vom anfordernden Benutzeragenten als neue Ressource definiert werden kann, kann der Origin-Server die Ressource mit diesem URI erstellen.

PATCH ist in RFC 5789 definiert:

Die PATCH-Methode fordert an, dass eine Reihe von Änderungen , die in der Anforderungsentität beschrieben sind, auf die durch den Anforderungs-URI angegebene Ressource angewendet werden.

Auch gemäß RFC 2616 Abschnitt 9.1.2 ist PUT idempotent, PATCH nicht.

Schauen wir uns nun ein reales Beispiel an. Wenn ich POST bis /users mit den Daten {username: 'skwee357', email: '[email protected]'} mache und der Server in der Lage ist, eine Ressource zu erstellen, antwortet er mit 201 und dem Ressourcenstandort (wir nehmen an, dass /users/1 ) und jeder nächste Aufruf von GET /users/1 gibt {id: 1, username: 'skwee357', email: '[email protected]'} zurück.

Nehmen wir jetzt an, ich möchte meine E-Mail ändern. Eine E-Mail-Änderung wird als "eine Reihe von Änderungen" betrachtet und daher sollte ich /users/1 mit " patch document " PATCHEN. In meinem Fall wäre es ein json {email: '[email protected]'}. Der Server gibt dann 200 zurück (vorausgesetzt, die Berechtigung ist in Ordnung). Dies bringt mich zur ersten Frage:

  • PATCH ist NICHT idempotent. Dies wurde in RFC 2616 und RFC 5789 angegeben. Wenn ich jedoch dieselbe PATCH-Anfrage (mit meiner neuen E-Mail) stelle, erhalte ich denselben Ressourcenstatus (wobei meine E-Mail auf den angeforderten Wert geändert wird). Warum ist PATCH dann nicht idempotent?

PATCH ist ein relativ neues Verb (RFC wurde im März 2010 eingeführt) und soll das Problem des "Patchen" oder Änderns einer Reihe von Feldern lösen. Vor der Einführung von PATCH verwendeten alle Benutzer PUT, um die Ressource zu aktualisieren. Aber nachdem PATCH eingeführt wurde, bin ich verwirrt, wofür PUT dann verwendet wird. Und das bringt mich zur zweiten (und wichtigsten) Frage:

  • Was ist der wahre Unterschied zwischen PUT und PATCH? Ich habe irgendwo gelesen, dass der PUT verwendet werden könnte, um die gesamte Entität unter einer bestimmten Ressource zu ersetzen mit PATCH). Was ist der wirkliche praktische Nutzen für einen solchen Fall? Wann möchten Sie eine Entität unter einem bestimmten Ressourcen-URI ersetzen/überschreiben und warum wird eine solche Operation nicht als Aktualisierung/Patching der Entität angesehen? Der einzige praktische Anwendungsfall, den ich für PUT sehe, ist die Ausgabe einer PUT-on-Sammlung, d. H. /users, um die gesamte Sammlung zu ersetzen. Das Ausgeben von PUT für eine bestimmte Entität macht nach der Einführung von PATCH keinen Sinn. Liege ich falsch?
569

NOTE: Als ich zum ersten Mal etwas über REST las, war Idempotenz ein verwirrendes Konzept, um zu versuchen, es richtig zu machen. Ich habe es in meiner ursprünglichen Antwort immer noch nicht ganz richtig verstanden, wie weitere Kommentare (und Jason Hoetgers Antwort ) gezeigt haben. Eine Weile habe ich mich geweigert, diese Antwort ausgiebig zu aktualisieren, um Jason nicht effektiv zu plagiieren, aber ich bearbeite sie jetzt, weil ich (in den Kommentaren) darum gebeten wurde.

Nachdem ich meine Antwort gelesen habe, schlage ich vor, dass Sie auch Jason Hoetgers ausgezeichnete Antwort auf diese Frage lesen, und ich werde versuchen, meine Antwort zu verbessern, ohne einfach von Jason zu stehlen.

Warum ist PUT idempotent?

Wie Sie in Ihrem RFC 2616-Zitat festgestellt haben, gilt PUT als idempotent. Wenn Sie eine Ressource PUTEN, spielen diese beiden Annahmen eine Rolle:

  1. Sie beziehen sich auf eine Entität, nicht auf eine Sammlung.

  2. Die von Ihnen bereitgestellte Entität ist vollständig (die gesamte Entität).

Schauen wir uns eines Ihrer Beispiele an.

{ "username": "skwee357", "email": "[email protected]" }

Wenn Sie POST dieses Dokument an /users senden, wie Sie vorschlagen, erhalten Sie möglicherweise eine Entität wie

## /users/1

{
    "username": "skwee357",
    "email": "[email protected]"
}

Wenn Sie diese Entität später ändern möchten, wählen Sie zwischen PUT und PATCH. Ein PUT könnte so aussehen:

PUT /users/1
{
    "username": "skwee357",
    "email": "[email protected]"       // new email address
}

Sie können dasselbe mit PATCH erreichen. Das könnte so aussehen:

PATCH /users/1
{
    "email": "[email protected]"       // new email address
}

Sie werden sofort einen Unterschied zwischen diesen beiden feststellen. Der PUT enthielt alle Parameter dieses Benutzers, aber PATCH enthielt nur den Parameter, der geändert wurde (email).

Bei Verwendung von PUT wird davon ausgegangen, dass Sie die vollständige Entität senden und dass die vollständige Entität eine vorhandene Entität an dieser URI ersetzt . Im obigen Beispiel erreichen PUT und PATCH dasselbe Ziel: Sie ändern beide die E-Mail-Adresse dieses Benutzers. PUT übernimmt dies jedoch, indem es die gesamte Entität ersetzt, während PATCH nur die bereitgestellten Felder aktualisiert und die anderen in Ruhe lässt.

Da PUT-Anforderungen die gesamte Entität einschließen, sollte sie immer dasselbe Ergebnis haben, wenn Sie dieselbe Anforderung wiederholt ausgeben (die von Ihnen gesendeten Daten sind jetzt die gesamten Daten der Entität). Daher ist PUT idempotent.

PUT falsch verwenden

Was passiert, wenn Sie die obigen PATCH-Daten in einer PUT-Anfrage verwenden?

GET /users/1
{
    "username": "skwee357",
    "email": "[email protected]"
}
PUT /users/1
{
    "email": "[email protected]"       // new email address
}

GET /users/1
{
    "email": "[email protected]"      // new email address... and nothing else!
}

(Für die Zwecke dieser Frage gehe ich davon aus, dass der Server keine bestimmten erforderlichen Felder hat und dies zulassen würde. Dies ist in der Realität möglicherweise nicht der Fall.)

Da wir PUT verwendet haben, aber nur email geliefert haben, ist dies nun das einzige in dieser Entität. Dies hat zu Datenverlust geführt.

Dieses Beispiel dient nur zur Veranschaulichung. Tun Sie dies niemals. Diese PUT-Anfrage ist technisch idempotent, aber das heißt nicht, dass es keine schreckliche, kaputte Idee ist.

Wie kann PATCH idempotent sein?

Im obigen Beispiel war PATCH idempotent. Sie haben eine Änderung vorgenommen, aber wenn Sie dieselbe Änderung immer wieder vorgenommen haben, hat dies immer das gleiche Ergebnis zur Folge: Sie haben die E-Mail-Adresse in den neuen Wert geändert.

GET /users/1
{
    "username": "skwee357",
    "email": "[email protected]"
}
PATCH /users/1
{
    "email": "[email protected]"       // new email address
}

GET /users/1
{
    "username": "skwee357",
    "email": "[email protected]"       // email address was changed
}
PATCH /users/1
{
    "email": "[email protected]"       // new email address... again
}

GET /users/1
{
    "username": "skwee357",
    "email": "[email protected]"       // nothing changed since last GET
}

Mein ursprüngliches Beispiel wurde aus Genauigkeitsgründen korrigiert

Ich hatte ursprünglich Beispiele, von denen ich dachte, dass sie nicht idempotent sind, aber sie waren irreführend/falsch. Ich werde die Beispiele behalten, aber sie verwenden, um eine andere Sache zu veranschaulichen: dass mehrere PATCH-Dokumente gegen dieselbe Entität, die verschiedene Attribute modifizieren, die PATCHes nicht idempotent machen.

Angenommen, zu einem früheren Zeitpunkt wurde ein Benutzer hinzugefügt. Dies ist der Zustand, von dem Sie ausgehen.

{
  "id": 1,
  "name": "Sam Kwee",
  "email": "[email protected]",
  "address": "123 Mockingbird Lane",
  "city": "New York",
  "state": "NY",
  "Zip": "10001"
}

Nach einem PATCH haben Sie eine geänderte Entität:

PATCH /users/1
{"email": "[email protected]"}

{
  "id": 1,
  "name": "Sam Kwee",
  "email": "[email protected]",    // the email changed, yay!
  "address": "123 Mockingbird Lane",
  "city": "New York",
  "state": "NY",
  "Zip": "10001"
}

Wenn Sie Ihren PATCH dann wiederholt anwenden, erhalten Sie weiterhin das gleiche Ergebnis: Die E-Mail wurde auf den neuen Wert geändert. A geht rein, A kommt raus, daher ist dies idempotent.

Eine Stunde später, nachdem Sie einen Kaffee gekocht und eine Pause eingelegt haben, kommt jemand anderes mit seinem eigenen PATCH. Es scheint, dass die Post einige Änderungen vorgenommen hat.

PATCH /users/1
{"Zip": "12345"}

{
  "id": 1,
  "name": "Sam Kwee",
  "email": "[email protected]",  // still the new email you set
  "address": "123 Mockingbird Lane",
  "city": "New York",
  "state": "NY",
  "Zip": "12345"                      // and this change as well
}

Da sich dieser PATCH von der Post nicht mit E-Mails befasst, sondern nur mit der Postleitzahl, wenn er wiederholt angewendet wird, wird auch das gleiche Ergebnis erzielt: Die Postleitzahl wird auf den neuen Wert gesetzt. A geht rein, A kommt raus, daher ist dies auch idempotent.

Am nächsten Tag beschließen Sie, Ihren PATCH erneut zu senden.

PATCH /users/1
{"email": "[email protected]"}

{
  "id": 1,
  "name": "Sam Kwee",
  "email": "[email protected]",
  "address": "123 Mockingbird Lane",
  "city": "New York",
  "state": "NY",
  "Zip": "12345"
}

Ihr Patch hat den gleichen Effekt wie gestern: Er legt die E-Mail-Adresse fest. A ist reingegangen, A ist rausgekommen, daher ist dies auch idempotent.

Was ich in meiner ursprünglichen Antwort falsch gemacht habe

Ich möchte einen wichtigen Unterschied machen (etwas, was ich in meiner ursprünglichen Antwort falsch verstanden habe). Viele Server antworten auf Ihre REST Anfragen, indem sie den neuen Entitätsstatus mit Ihren Änderungen (falls vorhanden) zurücksenden. Wenn Sie also diese Antwort zurückerhalten, ist sie anders als gestern , da die Postleitzahl nicht stimmt die, die du zuletzt erhalten hast. Ihre Anfrage betraf jedoch nicht die Postleitzahl, sondern nur die E-Mail. Ihr PATCH-Dokument ist also immer noch idempotent - die E-Mail, die Sie in PATCH gesendet haben, ist jetzt die E-Mail-Adresse der Entität.

Wann ist PATCH also nicht idempotent?

Für eine vollständige Behandlung dieser Frage verweise ich Sie erneut auf Jason Hoetgers Antwort . Ich werde es dabei belassen, weil ich ehrlich gesagt nicht denke, dass ich diesen Teil besser beantworten kann, als er es bereits getan hat.

808
Dan Lowe

Obwohl Dan Lowes ausgezeichnete Antwort die Frage des OP nach dem Unterschied zwischen PUT und PATCH sehr gründlich beantwortete, ist seine Antwort auf die Frage, warum PATCH nicht idempotent ist, nicht ganz richtig.

Um zu zeigen, warum PATCH nicht idempotent ist, ist es hilfreich, mit der Definition von Idempotenz zu beginnen (von Wikipedia ):

Der Begriff idempotent wird umfassender verwendet, um eine Operation zu beschreiben, die bei ein- oder mehrmaliger Ausführung [...] dieselben Ergebnisse liefert. Eine idempotente Funktion hat die Eigenschaft f(f(x)). = f(x) für einen beliebigen Wert x.

In einer zugänglicheren Sprache könnte ein idempotenter PATCH wie folgt definiert werden: Nach dem PATCH einer Ressource mit einem Patch-Dokument ändern alle nachfolgenden PATCH-Aufrufe derselben Ressource mit demselben Patch-Dokument die Ressource nicht.

Umgekehrt ist eine nicht-idempotente Operation eine, bei der f(f(x))! = F (x), was für PATCH wie folgt angegeben werden könnte: Nach dem PATCH einer Ressource mit einem Patch-Dokument werden nachfolgende PATCH-Aufrufe ausgeführt Ändern Sie die Ressource mit demselben Patchdokument auf dieselbe Ressource.

Angenommen, es gibt eine/users-Ressource, und der Aufruf von GET /users gibt eine Liste von Benutzern zurück, um einen nicht idempotenten PATCH zu veranschaulichen.

[{ "id": 1, "username": "firstuser", "email": "[email protected]" }]

Anstelle von PATCHing/users/{id}, wie im Beispiel des OP, wird angenommen, dass der Server PATCHing/users zulässt. Lassen Sie uns diese PATCH-Anfrage absetzen:

PATCH /users
[{ "op": "add", "username": "newuser", "email": "[email protected]" }]

Unser Patch-Dokument weist den Server an, der Benutzerliste einen neuen Benutzer mit dem Namen newuser hinzuzufügen. Nachdem dies das erste Mal aufgerufen wurde, gab GET /users Folgendes zurück:

[{ "id": 1, "username": "firstuser", "email": "[email protected]" },
 { "id": 2, "username": "newuser", "email": "[email protected]" }]

Was passiert nun, wenn wir die genau gleiche PATCH-Anforderung wie oben ausgeben? (Für dieses Beispiel nehmen wir an, dass die Ressource/users doppelte Benutzernamen zulässt.) Das "op" ist "add", sodass ein neuer Benutzer zur Liste hinzugefügt wird und ein nachfolgender GET /users zurückgibt:

[{ "id": 1, "username": "firstuser", "email": "[email protected]" },
 { "id": 2, "username": "newuser", "email": "[email protected]" },
 { "id": 3, "username": "newuser", "email": "[email protected]" }]

Die/users-Ressource hat sich erneut geändert , obwohl wir den exakt gleichen PATCH gegen den genauen ausgegeben haben gleicher Endpunkt. Wenn unser PATCH f (x) ist, ist f(f(x)) nicht dasselbe wie f (x), und daher ist dieser bestimmte PATCH nicht idempotent .

Obwohl PATCH nicht garantiert idempotent ist , enthält die PATCH-Spezifikation nichts, was Sie daran hindert, alle PATCH-Vorgänge auf Ihrem bestimmten Server idempotent auszuführen. RFC 5789 erwartet sogar Vorteile aus idempotenten PATCH-Anforderungen:

Eine PATCH-Anforderung kann auf eine Weise ausgegeben werden, die idempotent ist, was auch dazu beiträgt, schlechte Ergebnisse von Kollisionen zwischen zwei PATCH-Anforderungen auf derselben Ressource in einem ähnlichen Zeitrahmen zu verhindern.

In Dans Beispiel ist seine PATCH-Operation tatsächlich idempotent. In diesem Beispiel hat sich die Entität/users/1 zwischen unseren PATCH-Anforderungen geändert, jedoch nicht aufgrund unserer PATCH-Anforderungen. Es war tatsächlich das andere Patch-Dokument der Post, das zur Änderung der Postleitzahl führte. Der unterschiedliche PATCH der Post ist ein anderer Vorgang. wenn unser PATCH f (x) ist, ist der PATCH der Post g (x). Idempotence gibt an, dass f(f(f(x))) = f(x), macht aber keine Garantien über f(g(f(x))).

281
Jason Hoetger

Ich war auch neugierig und habe ein paar interessante Artikel gefunden. Ich kann Ihre Frage möglicherweise nicht in vollem Umfang beantworten, aber dies liefert zumindest einige weitere Informationen.

http://restful-api-design.readthedocs.org/en/latest/methods.html

Der HTTP-RFC gibt an, dass PUT eine vollständig neue Ressourcendarstellung als Anforderungsentität annehmen muss. Dies bedeutet, dass, wenn zum Beispiel nur bestimmte Attribute bereitgestellt werden, diese entfernt werden sollten (d. H. Auf null gesetzt werden).

Vor diesem Hintergrund sollte ein PUT das gesamte Objekt senden. Zum Beispiel,

/users/1
PUT {id: 1, username: 'skwee357', email: '[email protected]'}

Dies würde die E-Mail effektiv aktualisieren. Der Grund, warum PUT möglicherweise nicht zu effektiv ist, besteht darin, dass Sie nur ein Feld wirklich ändern und den Benutzernamen mit einbeziehen, was irgendwie nutzlos ist. Das nächste Beispiel zeigt den Unterschied.

/users/1
PUT {id: 1, email: '[email protected]'}

Wenn nun der PUT gemäß der Spezifikation entworfen wurde, würde der PUT den Benutzernamen auf null setzen und Sie würden das Folgende zurückbekommen.

{id: 1, username: null, email: '[email protected]'}

Wenn Sie einen PATCH verwenden, aktualisieren Sie nur das von Ihnen angegebene Feld und lassen den Rest wie in Ihrem Beispiel in Ruhe.

Die folgende Einstellung des PATCH ist etwas anders als ich es noch nie gesehen habe.

http://williamdurand.fr/2014/02/14/please-do-not-patch-like-an-idiot/

Der Unterschied zwischen den Anforderungen PUT und PATCH spiegelt sich in der Art und Weise wider, wie der Server die eingeschlossene Entität verarbeitet, um die durch den Anforderungs-URI angegebene Ressource zu ändern. In einer PUT-Anforderung wird die eingeschlossene Entität als geänderte Version der auf dem Origin-Server gespeicherten Ressource betrachtet, und der Client fordert das Ersetzen der gespeicherten Version an. Mit PATCH enthält die beigefügte Entität jedoch eine Reihe von Anweisungen, die beschreiben, wie eine Ressource, die sich derzeit auf dem Origin-Server befindet, geändert werden sollte, um eine neue Version zu erstellen. Die PATCH-Methode wirkt sich auf die durch den Request-URI identifizierte Ressource aus und kann auch Nebenwirkungen auf andere Ressourcen haben. d.h. neue Ressourcen können durch die Anwendung eines PATCH erstellt oder bestehende modifiziert werden.

PATCH /users/123

[
    { "op": "replace", "path": "/email", "value": "[email protected]" }
]

Sie behandeln den PATCH mehr oder weniger als eine Möglichkeit, ein Feld zu aktualisieren. Anstatt das Teilobjekt zu senden, senden Sie die Operation. d.h. E-Mail durch Wert ersetzen.

Der Artikel endet damit.

Es ist erwähnenswert, dass PATCH nicht wirklich für echte REST-APIs entwickelt wurde, da die Dissertation von Fielding keine Möglichkeit definiert, Ressourcen teilweise zu ändern. Roy Fielding selbst sagte jedoch, dass PATCH etwas war, das für den anfänglichen HTTP/1.1-Vorschlag erstellt wurde, da partielles PUT niemals RESTful ist. Sicher, Sie übertragen keine vollständige Darstellung, aber REST erfordert ohnehin keine vollständigen Darstellungen.

Nun, ich weiß nicht, ob ich dem Artikel besonders zustimme, wie viele Kommentatoren betonen. Das Senden über eine Teildarstellung kann leicht eine Beschreibung der Änderungen sein.

Für mich bin ich gemischt mit PATCH. Zum größten Teil werde ich PUT als PATCH behandeln, da der einzige wirkliche Unterschied, den ich bisher bemerkt habe, darin besteht, dass PUT fehlende Werte auf null setzt. Es ist vielleicht nicht die 'korrekteste' Methode, aber viel Glück beim Programmieren.

70
Kalel Wade

Der Unterschied zwischen PUT und PATCH besteht darin, dass:

  1. PUT muss idempotent sein. Um dies zu erreichen, müssen Sie die gesamte Ressource in den Anforderungshauptteil einfügen.
  2. PATCH kann nicht idempotent sein. Was impliziert, dass es in einigen Fällen, wie den von Ihnen beschriebenen Fällen, auch idempotent sein kann.

PATCH benötigt eine "Patch-Sprache", um dem Server mitzuteilen, wie die Ressource geändert werden soll. Der Aufrufer und der Server müssen einige "Operationen" definieren, wie "Hinzufügen", "Ersetzen", "Löschen". Zum Beispiel:

GET /contacts/1
{
  "id": 1,
  "name": "Sam Kwee",
  "email": "[email protected]",
  "state": "NY",
  "Zip": "10001"
}

PATCH /contacts/1
{
 [{"operation": "add", "field": "address", "value": "123 main street"},
  {"operation": "replace", "field": "email", "value": "[email protected]"},
  {"operation": "delete", "field": "Zip"}]
}

GET /contacts/1
{
  "id": 1,
  "name": "Sam Kwee",
  "email": "[email protected]",
  "state": "NY",
  "address": "123 main street",
}

Anstatt explizite "Operations" -Felder zu verwenden, kann die Patch-Sprache dies implizit machen, indem Konventionen wie die folgenden definiert werden:

im PATCH-Anforderungshauptteil:

  1. Die Existenz eines Feldes bedeutet "Ersetzen" oder "Hinzufügen" dieses Feldes.
  2. Wenn der Wert eines Feldes null ist, bedeutet dies, dass dieses Feld gelöscht wird.

Mit der obigen Konvention kann der PATCH im Beispiel die folgende Form annehmen:

PATCH /contacts/1
{
  "address": "123 main street",
  "email": "[email protected]",
  "Zip":
}

Was übersichtlicher und benutzerfreundlicher aussieht. Die Benutzer müssen sich jedoch der zugrunde liegenden Konvention bewusst sein.

Mit den oben erwähnten Operationen ist der PATCH immer noch idempotent. Wenn Sie jedoch Operationen wie "Inkrementieren" oder "Anhängen" definieren, können Sie leicht erkennen, dass diese nicht mehr idempotent sind.

13
Bin Ni

Lassen Sie mich das RFC 7231 Abschnitt 4.2.2 , das bereits in früheren Kommentaren zitiert wurde, genauer zitieren und kommentieren:

Eine Anforderungsmethode wird als "idempotent" betrachtet, wenn die beabsichtigte Auswirkung mehrerer identischer Anforderungen mit dieser Methode auf den Server dieselbe ist wie die Auswirkung für eine einzelne solche Anforderung. Von den in dieser Spezifikation definierten Anforderungsmethoden sind die Methoden PUT, DELETE und Safe Request idempotent.

(...)

Idempotente Methoden zeichnen sich dadurch aus, dass die Anforderung automatisch wiederholt werden kann, wenn ein Kommunikationsfehler auftritt, bevor der Client die Antwort des Servers lesen kann. Wenn ein Client beispielsweise eine PUT-Anforderung sendet und die zugrunde liegende Verbindung geschlossen wird, bevor eine Antwort empfangen wird, kann der Client eine neue Verbindung herstellen und die idempotente Anforderung erneut versuchen. Es ist bekannt, dass das Wiederholen der Anforderung den gleichen beabsichtigten Effekt hat, auch wenn die ursprüngliche Anforderung erfolgreich war, obwohl die Antwort möglicherweise unterschiedlich ist.

Was sollte also nach einer wiederholten Anfrage einer idempotenten Methode "dasselbe" sein? Nicht der Serverstatus, noch die Serverantwort, sondern der beabsichtigte Effekt . Insbesondere sollte die Methode "aus Sicht des Kunden" idempotent sein. Nun, ich denke, dieser Standpunkt zeigt, dass das letzte Beispiel in Dan Lowes Antwort , das ich hier nicht plagiieren möchte, tatsächlich zeigt, dass eine PATCH-Anfrage nicht idempotent sein kann (in a natürlicher als das Beispiel in Jason Hoetgers Antwort ).

In der Tat wollen wir das Beispiel etwas präziser machen, indem wir explizit eine Absicht für den ersten Client ermöglichen. Angenommen, dieser Client durchsucht die Liste der Benutzer mit dem Projekt, um ihre E-Mails und Postleitzahlen zu überprüfen. Er beginnt mit Benutzer 1 und stellt fest, dass die Postleitzahl stimmt, die E-Mail aber falsch ist. Er beschließt, dies mit einer PATCH-Anfrage zu korrigieren, die völlig legitim ist, und sendet nur

PATCH /users/1
{"email": "[email protected]"}

da dies die einzige korrektur ist. Jetzt schlägt die Anforderung aufgrund eines Netzwerkproblems fehl und wird einige Stunden später automatisch erneut gesendet. In der Zwischenzeit hat ein anderer Client die Postleitzahl von Benutzer 1 (irrtümlich) geändert. Wenn Sie dieselbe PATCH-Anforderung ein zweites Mal senden, wird der beabsichtigte Effekt nicht erreicht des Kunden, da wir am Ende eine falsche Zip haben. Daher ist die Methode im Sinne des RFC nicht idempotent.

Wenn der Client stattdessen eine PUT-Anforderung verwendet, um die E-Mail zu korrigieren, und alle Eigenschaften von Benutzer 1 zusammen mit der E-Mail an den Server sendet, wird seine beabsichtigte Wirkung erreicht, auch wenn die Anforderung später erneut gesendet werden muss und Benutzer 1 geändert wurde in der Zwischenzeit --- seit der zweiten PUT-Anforderung werden alle Änderungen seit der ersten Anforderung überschrieben.

3
Rolvernew
0
jobima