Was ist eine idempotente Operation?
Einführung
In diesem Artikel werden wir sehen, was eine idempotente Operation ist, warum Idempotenz nützlich ist, und wir werden Idempotenz in REST betrachten.
Was ist Idempotenz?
Einfach ausgedrückt, können wir eine idempotente Operation mehrmals ausführen, ohne das Ergebnis zu ändern.
Des Weiteren darf die Operation nach der ersten erfolgreichen Ausführung keine Nebenwirkungen verursachen.
Schauen wir uns zwei einfache Beispiele an.
2.1. Absolutwert
Eine Funktion, die den absoluten Wert zurückgibt, ist idempotent; egal wie oft wir sie auf dieselbe Zahl anwenden, sie gibt immer das gleiche Ergebnis zurück.
Betrachten wir die Funktion:
Dann gilt Folgendes:
Beispiel:
Im Gegensatz dazu, eine Funktion, die das Vorzeichen einer Zahl umdreht, ist nicht idempotent:
Dann:
Beispiel:
2.2. Adresse aktualisieren
Ein weiteres praktisches Beispiel für eine idempotente Operation wäre die Aktualisierung der Kontaktdaten eines Benutzers im System. Angenommen, wir aktualisieren nur die Telefonnummer. Der Nebeneffekt dieses Updates ist, dass wir eine SMS mit einem Bestätigungscode an die neue Nummer senden. Wir haben drei mögliche Szenarien:
- Die erste Aktualisierungsnachricht wurde erfolgreich verarbeitet, die Nummer wurde im System aktualisiert und die Textnachricht wurde gesendet. Wenn die Update-Nachricht erneut gesendet wird, passiert nichts. Außerdem wird die Textnachricht kein zweites Mal gesendet.
- Das erste Update schlägt fehl. Das System wird nicht aktualisiert und es wird keine Textnachricht gesendet. Wenn das zweite Update erfolgreich ist, wird das System aktualisiert und die Textnachricht gesendet.
- Das erste Update schlägt fehl. Bevor ein weiteres Update gesendet wird, wird der Benutzer im System deaktiviert. Da sich der Systemstatus geändert hat, wirkt sich eine zweite Aktualisierung der Telefonnummer nicht aus.
Warum Idempotenz?
Idempotenz stellt sicher, dass dieselbe Anforderung zu demselben Systemstatus führt und keine Aktion unbeabsichtigt mehr als einmal ausgeführt wird.
Betrachten wir als Beispiel eine Anfrage des Absenders S, Geld über einen Zahlungsdienst PS an den Empfänger R zu senden.
3.1. Nicht-idempotentes Beispiel
Hier ist die nicht-idempotente Version der Anforderung:
Beim ersten Versuch sendet S eine Anforderung zum Senden von $ 10 an R. PS empfängt die Nachrichten. PS sends gibt eine Fehlermeldung an S zurück, der diese Nachricht aufgrund eines Netzwerkfehlers nicht empfängt.
S weiß nicht, ob die Übertragung erfolgreich war, also versucht er es erneut. Dieses Mal ist die Übertragung an R erfolgreich und PS sendet eine Bestätigungsnachricht an S. Die Bestätigung schlägt erneut fehl und S weiß nicht, ob die Übertragung erfolgreich war oder nicht.
Deshalb versucht er es zum dritten Mal. PS empfängt die Nachricht, betrachtet sie als neue Anfrage, sendet das Geld an R und sendet eine Bestätigung an S zurück.
Dies ist keine idempotente Anfrage, da wir dieselbe Zahlung wiederholen und nicht zweimal senden wollten.
3.2. Idempotenzschlüssel
Zahlungen sind ein gutes Beispiel, um zu veranschaulichen, warum Idempotenz nützlich ist. Im vorherigen Beispiel haben wir gesehen, dass die Zahlung an R mehrmals ausgeführt wird, da S in den Ruhestand geht, ohne zu wissen, dass die Überweisung bereits erfolgreich war.
Wenn die Operation idempotent wäre, wäre dies nicht der Fall gewesen. Aber woher weiß PS, dass S gerade dieselbe Zahlung wiederholt hat und keine zweite Zahlung von 10 US-Dollar an S senden möchte?
Um dies zu erreichen, enthält S einen Idempotenzschlüssel in seiner Anfrage an PS. Dieser Schlüssel kann beispielsweise eine UUID sein. Wenn PS eine Anforderung mit demselben Idempotenzschlüssel empfängt, weiß es, dass es sich um einen erneuten Versuch handelt. Wenn es den Schlüssel noch nicht gesehen hat, weiß es, dass es sich um eine neue Anfrage handelt.
Schauen wir uns die idempotente Version des vorherigen Beispiels an:
Hier sind der erste Versuch und die erste Wiederholung die gleichen wie in der nicht-idempotenten Version, außer dass die Anforderung den Idempotenzschlüssel enthält (65TH68M5 in unserem Beispiel).
Der wichtige Unterschied ist der zweite Versuch: PS empfängt die Nachricht, stellt fest, dass eine Nachricht mit demselben Idempotenzschlüssel bereits erfolgreich verarbeitet wurde, und gibt eine Bestätigung an S zurück, ohne das Geld erneut an R zu senden.
Hier besteht der Vorteil der Idempotenz darin, dass S es so oft wiederholen kann, wie er möchte, ohne sich um eine doppelte Zahlung kümmern zu müssen. PS muss sich keine Sorgen machen, dass S die Bestätigung erhält, da er weiß, dass S es erneut versuchen kann, falls er die Nachricht nicht erhalten hat.
Der Nachteil dieses Ansatzes ist, dass PS alle empfangenen Schlüssel speichern muss. Dies kann in Ordnung sein, wenn nicht viele Anfragen vorliegen; wenn die Anforderungshäufigkeit jedoch sehr hoch ist, kann dies problematisch sein. Eine Lösung kann darin bestehen, den Idempotenzschlüssel nach einiger Zeit ablaufen zu lassen.
Idempotenz und RUHE
4.1. Übersicht
Werfen wir einen kurzen Blick darauf, wie Idempotenz auf HTTP-Verben angewendet wird, die wichtig zu verstehen sind, wenn wir eine REST-API erstellen möchten. Eine sehr detaillierte Referenz aller HTTP-Verben finden Sie in RFC 7231.
Die folgende Tabelle zeigt, welche Verben idempotent sind (oder sein sollten).
4.2. Idempotente Operationen
GET, HEAD und OPTION sind eindeutig idempotent, da sie nur Daten lesen, aber keine Ressourcen erstellen, aktualisieren oder löschen.
PUT ist idempotent, da es eine Ressource aktualisiert oder eine neue erstellt, wenn sie nicht existiert. Wenn wir dasselbe Update mehrmals gesendet haben, sollte sich die Ressource nicht ändern.
4.3. Nicht-idempotente Operationen
POST muss nicht idempotent sein, da es eine neue Ressource erstellt und bei erneutem Aufruf normalerweise eine andere Ressource erstellt. Es kann jedoch auch als idempotente Operation implementiert werden.
Die PATCH-Operation aktualisiert eine Ressource teilweise und muss nicht unbedingt idempotent sein. Schauen wir uns ein Beispiel an, um den Unterschied zwischen PUT und PATCH besser zu verstehen:
Angenommen, wir möchten einen Artikel in einem Online-Shop in einen Warenkorb legen. Wenn wir PUT verwenden, müssen wir die vollständigen Warenkorbdaten senden, einschließlich aller Artikel, die sich bereits im Warenkorb befinden. Mit PATCH können wir nur den Artikel senden, der hinzugefügt werden soll, und er wird an die Liste der Artikel angehängt, die sich bereits im Warenkorb befinden.
Wenn wir die PATCH-Anfrage erneut senden, wird dasselbe Element erneut hinzugefügt. Natürlich können wir für POST auch einen idempotenten PATCH implementieren.
4.4. HTTP-Antwort
Es ist wichtig zu beachten, dass mehrere Aufrufe einer idempotenten Operation nicht unbedingt zu derselben HTTP-Antwort führen.
PUT gibt beispielsweise 201 (Erstellt) zurück, wenn eine Ressource erstellt wurde, oder 200 (OK) oder 203 (Kein Inhalt), wenn eine Ressource aktualisiert wurde.
Ein DELETE kann beispielsweise 200 (OK) oder 204 (Kein Inhalt) zurückgeben, wenn ein tatsächliches Löschen stattfindet. Alle nachfolgenden Aufrufe geben 404 (Nicht gefunden) zurück.
Fazit
In diesem Artikel haben wir gesehen, was Idempotenz bedeutet, welche Vorteile Idempotenz hat und wie sie sich auf RUHE bezieht.
Obwohl die allgemeine Bedeutung von Idempotenz leicht zu verstehen ist, kann es ziemlich schwierig sein, alle Feinheiten wie Nebenwirkungen und HTTP-Antworten während des Entwurfs einer API zu berücksichtigen.
Leave a Reply