Welches HTTP-Verb soll ich verwenden, um eine Aktion in einem REST-Webdienst auszulösen?

80

Ich implementiere einen RESTful-Webdienst und eine der verfügbaren Aktionen wird ausgeführt reload. Es wird verwendet, um Konfigurationen, Cache usw. neu zu laden.

Wir haben mit einem einfachen GETzu einem URI wie diesem begonnen: ${path}/cache/reload(Es werden keine Parameter übergeben, nur der URI wird aufgerufen). Mir ist bekannt, dass Daten bei einer GET-Anfrage nicht geändert werden dürfen.

Welches ist das richtige Verb, um eine Aktion / einen Befehl in einem RESTful-Webdienst aufzurufen?

Das Neuladen ist ein Befehl des REST-Webdienstes, der seinen eigenen Cache / Konfiguration / etc neu lädt. Es ist keine Methode, die Informationen an den Client zurückgibt.

Wahrscheinlich ist das, was ich versuche, nicht REST, aber es ist immer noch etwas, das auf diese Weise getan werden muss. Die reloadMethode war nur ein reales Beispiel, das im Anwendungsbereich Sinn macht, und die meisten Antworten konzentrierten sich darauf. Tatsächlich musste ich nur wissen, welches Verb eine Aktion auslösen sollte, die CRUD nicht ausführt, aber dennoch Daten ändert. Zustand.

Ich fand diesen detaillierten Hinweis auf Stack Overflow über das Thema: https://stackoverflow.com/questions/16877968/

Renato Dinhani
quelle
1
"Neu laden" ist das Gefühl, dass eine App die angezeigten Daten aktualisiert? Gibt es einen Unterschied zwischen dem erneuten Laden und dem erneuten Abrufen der Daten?
Sean Redmond
1
@SeanRedmond Nein, die Daten werden nicht an den Client gesendet. Tatsächlich fordert der Client den REST-Webdienst auf, einen internen Befehl auszuführen (neu zu laden). So etwas wie: "Viele Konfigurationen wurden in der Datenbank geändert. REST-Webdienst lädt sie jetzt in Ihren Speicher zurück."
Renato Dinhani
Cross-Site-Duplikat: stackoverflow.com/q/15340946/319403
cHao
Haben Sie darüber nachgedacht, bei entsprechenden Anforderungen einen Header-Parameter zu verwenden? Dies klingt sehr nach einer Cache-Aktualisierung ...
Guran

Antworten:

25

Ich glaube nicht, dass es ein richtiges Verb für diese Aktion gibt, da diese Transaktion nicht wirklich "RESTful" ist. Das "s" und "t" stehen für "state transfer" und hier wird nichts übertragen. Oder anders ausgedrückt, nach der strengsten Definition werden Verben wie PUT und POST immer mit einem Substantiv verwendet und "reload" hat nur das Verb.

Dieses Neuladen mag nicht RESTful sein, aber es kann trotzdem nützlich sein und Sie müssen nur einen Weg wählen, um es zu tun und damit zu leben oder zu erklären, dass es ungewöhnlich ist. GET ist wahrscheinlich das einfachste. In den Kommentaren ist jedoch einiges an Skepsis zu spüren, daher sollten Sie überlegen, ob diese Aktion zum erneuten Laden erforderlich ist, da etwas anderes nicht genau das tut, was es tun sollte.

Sean Redmond
quelle
Ich bin damit einverstanden, dass dies nicht RESTful ist, aber nützlich sein kann. Ich denke, Sie sollten einen PUT empfehlen, da dies wahrscheinlich idempotent, aber nicht nullimpotent ist.
Aaron Greenwald
@ Aaron, der Vergleich von idempotent und nullimpotent ist alles in Ordnung und gut, aber wie bestimmen Sie, wann es nicht impotent ist?
Craig
@Craig es ist idempotent, wenn es mehrmals ausgeführt wird, hat das den gleichen Effekt wie wenn es einmal ausgeführt wird. Es ist nullpotent, wenn es ein- oder mehrmals ausgeführt wird und auf dem Server dieselbe Auswirkung hat wie nullmaliges Ausführen. en.wikipedia.org/wiki/Idempotence
Aaron Greenwald
5
@AaronGreenwald “notimpotent” [nicht-im-poht-nt] [nicht-im-pawr-tnt] - Adjektiv - 1. Ein Wortspiel, “nicht wichtig”, Antonyme des Adjektivs “wichtig”. 2. Humor… ;-)
Craig
@ Craig Ich habe das komplett verpasst :)
Aaron Greenwald
75

Wenn Sie RESTful sein möchten, denken Sie nicht an das Verb, mit dem eine Aktion ausgeführt werden soll, sondern an den Zustand , in dem sich die Ressource befinden soll, nachdem der Client etwas getan hat.

Wenn Sie eines Ihrer obigen Beispiele verwenden, haben Sie eine E-Mail-Warteschlange, in der E-Mails gesendet werden. Sie möchten, dass der Client diese E-Mail-Warteschlange in den Status "Angehalten" oder "Angehalten" versetzt.

Der Client legt also einen neuen Status für diese Ressource auf dem Server an. So einfach kann JSON sein

PUT http://myserver.com/services/email_service HTTP/1.1
Content-Type: text/json

{"status":"paused"}

Der Server findet heraus, wie er vom aktuellen Status (z. B. "Laufen") zum Status "Angehalten" / "Angehalten" gelangen kann.

Wenn der Client ein GET für die Ressource ausführt, sollte er den Status zurückgeben, in dem er sich gerade befindet (sagen wir "pausiert").

Der Grund dafür und warum REST so leistungsfähig sein kann, ist, dass Sie das WIE verlassen, um den Server in diesen Zustand zu versetzen.

Der Client sagt nur "Dies ist der Zustand, in dem Sie sich jetzt befinden sollten" und der Server findet heraus, wie dies erreicht werden kann. Es könnte sich um ein einfaches Umblättern in einer Datenbank handeln. Möglicherweise sind Tausende von Aktionen erforderlich. Dem Kunden ist es egal und er muss es nicht wissen.

Sie können also komplett umschreiben / umgestalten, wie der Server das macht, und der Client kümmert sich nicht darum. Der Client muss nur die verschiedenen Zustände (und deren Darstellungen) einer Ressource kennen, keine der Interna.

Cormac Mulhall
quelle
2
Für mich ist das die richtige Antwort. Das Aktualisieren von Daten auf dem Server ist kein idempotenter Vorgang und GETein völlig unangemessenes Verb. PUTist das am besten geeignete Verb, da die Operation als Aktualisierung des "reloaded status" des Caches auf "reloaded" angesehen werden kann.
Jez
@Jez Von den Antworten hier bevorzuge ich auch diese. Das Festhalten an der E - Mail - Metapher, Stegreif es sich zunächst seltsam fühlen , die Post zu denken , zu senden , indem sie in den „Senden“ Staat statt nur darum , zu senden es (eine Aktion). Aber wenn Sie darüber nachdenken, ist das wirklich dasselbe, als wenn Sie es in den "Postausgang" legen. Tatsächlich stellt das Mail-System es wahrscheinlich intern so in die Warteschlange, wenn Sie es zum Senden auffordern. So kann die API Sie die E-Mail in den Status "Senden" versetzen, und die API ist nicht verpflichtet, sich darüber hinaus zu erklären.
Craig
Wenn Sie also noch nicht möchten, dass die Nachricht verschickt wird, versetzen Sie sie in den Status "geplant" mit einem Datum und einer Uhrzeit, zu der sie veröffentlicht werden soll. Wenn es nicht vollständig ist, versetzen Sie es (oder es ist implizit / standardmäßig) in den Zustand "Entwurf" usw.
Craig
... obwohl ich denke, dass ich in diesem Fall POST PUT vorziehen würde, da PUT auch idempotent sein soll, aber POST unter keiner solchen Einschränkung steht.
Craig
1
Sie könnten das tun, aber letztendlich wird versucht, einen quadratischen Stift in ein rundes Loch zu stecken. Es gibt keinen Grund, warum der Client den Server auslösen muss, um etwas "neu zu laden", was nur ein schlechtes Architekturdesign ist. Entweder kann der Server seinen internen Status bei jedem Anruf oder in einem festgelegten Zeitintervall aktualisieren. Es ist keine REST-konforme Architektur, sich darauf zu verlassen, dass der Client dem Server anweist, unabhängig von einer tatsächlichen Anforderung nach einem Ressourcenzustand etwas neu zu laden.
Cormac Mulhall
32

Einige der anderen Antworten, einschließlich der akzeptierten, empfehlen die Verwendung eines GET (wenn auch nicht sehr enthusiastisch).

Ich stimme dir nicht zu.

Zuallererst sind alle anderen, die Ihnen sagen, dass dies nicht ideal und nicht wirklich erholsam ist, richtig. In einem ordnungsgemäßen REST-Szenario bearbeiten Sie Ressourcen auf dem Server und fügen diese Ressourcen hinzu, aktualisieren, löschen, abrufen usw. Ein PUT sollte eine Nutzlast senden, die angibt, wie die Ressource lauten soll, wenn die Anforderung abgeschlossen ist, und ein POST sollte eine Nutzlast senden, die eine Ressource darstellt, die dem Server hinzugefügt werden soll. Und ein GET sollte eine Ressource auf dem Server zurückgeben.

Sie haben einen RPC (Remote Procedure Call), der nicht RESTful ist - Sie möchten etwas auf dem Server tun. Wenn Sie also versuchen, eine reine REST-API zu erstellen, sollten Sie überdenken, was Sie tun.

Das heißt, manchmal müssen Sie die Regeln ein wenig biegen. Vor allem, wenn Sie eine interne API entwickeln, die der Öffentlichkeit nicht zugänglich ist, können Sie entscheiden, dass sich der Kompromiss lohnt.

In diesem Fall würde ich einen PUT oder POST empfehlen, je nachdem, ob der RPC idempotent ist oder nicht.

Im Allgemeinen wird gesagt, dass HTTP PUT SQL UPDATE und HTTP POST SQL INSERT zugeordnet ist, dies ist jedoch nicht der Fall. Eine reinere Möglichkeit zu behaupten ist, dass HTTP PUT idempotent sein sollte und HTTP POST nicht. Dies bedeutet, dass Sie dieselbe PUT-Anfrage so oft aufrufen können, wie Sie möchten, ohne dass Nebenwirkungen auftreten. Sobald Sie es einmal angerufen haben, ist es harmlos, es erneut anzurufen. Sie sollten POST-Anforderungen jedoch nicht wiederholt aufrufen, es sei denn, Sie möchten - jeder POST ändert die Daten auf dem Server erneut.

In Ihrem Fall würde ich ein PUT empfehlen, wenn Sie diese Nachladefunktion benötigen, da es sich wie idempotent anhört. Aber ich möchte Sie dennoch dringend bitten, darüber nachzudenken, was die anderen darüber sagten, dass Sie es überhaupt nicht brauchen.

Aaron Greenwald
quelle
6

POSTund PUTsind die HTTP-Verben, mit denen eine Entität an einen Webserver übermittelt wird. Mit PUTist die übermittelte Entität die (neue) Darstellung für die Ressource bei der angegebenen URI, die nicht Ihren Wünschen entspricht. POSTDies gilt für den traditionellen Form-Handler, bei dem die Entität zusätzliche Daten für die Ressource enthält. Das ist also der Gewinner. Die Entität würde den Befehl oder die Aktion enthalten (zB "action = reload").

Das heißt, der betreffende Befehl sollte wahrscheinlich nicht über eine REST-Schnittstelle verfügbar gemacht werden. Es hört sich so an, als ob die Notwendigkeit eines "Nachladens" dadurch entsteht, dass Daten über einen anderen Kanal (z. B. Dateisystem, DB-Client) geändert werden können. Caches sollten transparent sein. Darüber hinaus sollten HTTP-Anforderungen atomar sein, auch unter Berücksichtigung von Nachrichten, die über andere Kanäle gesendet werden. Einen "reload" -Befehl für Konfigurationseinstellungen anzubieten, scheint eine unnötige Komplexität zu sein. Voraussetzung ist ein sprödes Design. "Reload" nach einem Update über einen anderen Kanal einer Bereinigung zu unterziehen, ist schmutzig, da ein Kanal nicht die gesamte Konversation enthält. Betrachten Sie stattdessen eine der folgenden Möglichkeiten:

  • Aktualisierungen vollständig über REST vornehmen
  • Setzen Sie die Befehle dem anderen Kanal aus
  • Automatisierung der Aktionen

Einige dieser Optionen sind möglicherweise nicht realisierbar, je nachdem, welche anderen Einschränkungen bestehen.

Siehe auch " PUT vs POST in REST ".

outis
quelle
Danke. Ich habe das "interne" der Bearbeitung entfernt, da die "reload" -Methode eigentlich öffentlich sein soll. Ich habe nur versucht zu meinen, es bezieht sich auf den Web-Service selbst. Ich denke, die "Aktion" zu posten, wäre ein guter Ansatz.
Renato Dinhani
@ RenatoDinhaniConceição: auch ohne das "interne" riecht es noch. Möglicherweise müssen Sie eine neue Frage stellen, ob das Design gut ist.
outis
4

Ich würde argumentieren, warum eine Client-Anfrage explizit einen Anruf tätigen müsste, um so etwas zu aktualisieren. Es hört sich so an, als ob dies entweder eine versteckte Logik bei einer typischeren Implementierung von GET sein sollte (d. H. Pull-Daten, aber der Dienst aktualisiert die Daten, bevor sie abgerufen werden) oder durch einen anderen Auslöser im Backend, der vom Client entfernt ist.

Immerhin müsste die data / config nur bei nachfolgenden Aufrufen aktuell sein, daher würde ich mich eher auf einen faulen oder eifrigen Aufruf für eine Datenaktualisierung stützen. Natürlich gehe ich hier von einer Menge aus, aber ich würde einen Schritt zurücktreten, um die Notwendigkeit eines solchen expliziten und eigenständigen Aufrufs neu zu bewerten.

Thomas Stringer
quelle
Schau dir meine Bearbeitung an. "reload" ist kein Befehl, der Daten zurückgibt. Es bezieht sich auf den REST-Webservice selbst. Im Allgemeinen bezieht sich meine Frage auf das Auslösen von Aktionen in einem REST-Webdienst. Ein anderes Beispiel kann sein: email_queue/stop_sending_emails. Ich gebe gerade einen Befehl an etwas mit einer REST-Schnittstelle.
Renato Dinhani
5
Ich stimme immer noch zu. Das Aufrufen von SIGHUP für einen lokalen Prozess ist sinnvoll, da der Computer einer lokal angemeldeten Person vertrauen sollte, die Zugriff auf dieses Signal hat. Aber für ein zustandsloses, über das Internet zugängliches Protokoll? Möglicherweise sollte der Webservice bei Bedarf automatisch per Abruf oder Dateiüberwachung neu geladen werden. Dieser Aufruf sollte völlig unnötig sein.
1
Genau. Dinge wie Konfiguration und Caching sollen für den Client transparent sein. Vielleicht sollten Sie uns eine konkretere Beschreibung einer Situation geben, in der Ihr Endpunkt aufgerufen werden würde.
Benjamin Hodgson
3

Warum behandeln Sie die Aktion nicht wie eine Ressource? Da Sie also den Cache aktualisieren möchten, würden Sie eine neue Aktion in Ihrem System POSTEN.

Für Puristen könnte man dafür eine eigene URL haben. Beachten Sie, dass Sie dies erweitern und die tatsächlichen Aktionen in einer Datenbank (oder einem beliebigen Speicher) mit Datum, Status, Benutzer usw. protokollieren können. Nur meine Gedanken hier.

Allgemeine systemweite Operation / actions / {action}

Operation, die für einen Ressourcentyp / actions / {resource} / {action} spezifisch ist

Vorgang spezifisch für eine Ressource / actions / {resource} / {id} / {action}

In Ihrem Fall ist der Cache wahrscheinlich systemweit / actions / reload_cache

Isometriq
quelle
0

Welches HTTP-Verb soll ich verwenden, um eine Aktion in einem REST-Webdienst auszulösen?

Bei der Betrachtung der Details eines REST-Service ist es oft nützlich, diese Heuristik zu berücksichtigen: Wie würden Sie dies mit einer Website implementieren?

HTML kann nur GET- und POST-Anforderungen nativ beschreiben. Also können wir loslegen und dort suchen.

Ist GETangebracht Um diese Frage zu beantworten, müssen wir über die Annahmen nachdenken, die Clients und Zwischenkomponenten machen dürfen GET. Die Semantik von GETist sicher

Der Client fordert keine Statusänderung auf dem Ursprungsserver an und erwartet dies nicht, da eine sichere Methode auf eine Zielressource angewendet wird. Ebenso ist nicht zu erwarten, dass eine vernünftige Verwendung einer sicheren Methode den Ursprungsserver schädigen, Eigentum verlieren oder ungewöhnlich belasten wird.

Die Implikation ist daher, dass die Clients und Zwischenkomponenten nach eigenem Ermessen eine GET-Anforderung so oft aufrufen können, wie dies zur Befriedigung ihrer eigenen Bedenken erforderlich ist. Spinnen können wahllos Ressourcen abrufen, um ihre Indizes zu aktualisieren. Caches können vorab abgerufen werden. In einem unzuverlässigen Netzwerk können verlorene Nachrichten so oft wie nötig wiederholt werden, um mindestens eine Antwort zu gewährleisten.

Es wird verwendet, um Konfigurationen, Cache usw. neu zu laden.

Wenn dies teure Aufgaben sind, möchten Sie möglicherweise nicht, dass die Kunden diese Anfragen nach eigenem Ermessen stellen.

POSTAuf der anderen Seite gibt es praktisch keine Einschränkungen - dies reduziert die Annahmen, die generische Clients machen dürfen, erheblich. Sie erhalten keine Komponenten, die spekulative POST-Anfragen stellen, da dies fehlerhaft wäre - nichts im Standard besagt, dass dies in Ordnung ist.

PUT, PATCH, DELETE... das sind unsichere Methoden mit präziser Semantik als POST; Ob sie angemessen sind oder nicht, hängt von Ihrem Ressourcenmodell ab.

Eine wichtige Idee ist, dass die HTTP-Methoden in die Dokumentdomäne gehören (siehe Jim Webbers Vortrag von 2011 ). Die beschriebenen Effekte sind wahrscheinlich nicht Teil der Dokumentdomäne, sondern werden stattdessen beim Ändern der Dokumente durch Nebenwirkungen hervorgerufen . Das gibt Ihnen viel Freiheit bei der Organisation Ihrer Dokumente, um die Arbeit zu erledigen.

VoiceOfUnreason
quelle