Rufen Sie eine serverseitige Methode für eine Ressource auf REST-fähige Weise auf


142

Denken Sie daran, ich habe ein rudimentäres Verständnis von REST. Angenommen, ich habe diese URL:

http://api.animals.com/v1/dogs/1/

Und jetzt möchte ich den Server dazu bringen, dass der Hund bellt. Nur der Server weiß, wie das geht. Nehmen wir an, ich möchte, dass es auf einem CRON-Job ausgeführt wird, bei dem der Hund für den Rest der Ewigkeit alle 10 Minuten bellt. Wie sieht dieser Anruf aus? Ich möchte das irgendwie tun:

URL-Anfrage:

ACTION http://api.animals.com/v1/dogs/1/

Im Anfragetext:

{"action":"bark"}

Bevor Sie sauer auf mich werden, weil ich meine eigene HTTP-Methode erfunden habe, helfen Sie mir und geben Sie mir eine bessere Vorstellung davon, wie ich eine serverseitige Methode auf RESTful-Weise aufrufen soll. :) :)

BEARBEITEN ZUR ERKLÄRUNG

Noch etwas Klarheit darüber, was die "Rinden" -Methode bewirkt. Hier sind einige Optionen, die zu unterschiedlich strukturierten API-Aufrufen führen können:

  1. bark sendet einfach eine E-Mail an dog.email und zeichnet nichts auf.
  2. bark sendet eine E-Mail an dog.email und erhöht dog.barkCount um 1.
  3. bark erstellt mit bark.timestamp einen neuen "bark" -Datensatz, wenn die Rinde aufgetreten ist. Außerdem wird dog.barkCount um 1 erhöht.
  4. bark führt einen Systembefehl aus, um die neueste Version des Hundecodes von Github abzurufen. Anschließend wird eine SMS an dog.owner gesendet, in der mitgeteilt wird, dass der neue Hundecode in Produktion ist.

14
Interessanterweise scheint das Hinzufügen eines Kopfgeldes schlechtere Antworten hervorgerufen zu haben als ursprünglich ;-) Beachten Sie bei der Bewertung der Antworten Folgendes: 1) Die Spezifikationen für die HTTP-Verben schließen jede andere Wahl als POST aus. 2) REST hat nichts mit der URL-Struktur zu tun - es handelt sich um eine allgemeine Liste von Einschränkungen (zustandslos, zwischenspeicherbar, geschichtet, einheitliche Schnittstelle usw.), die Vorteile (Skalierbarkeit, Zuverlässigkeit, Sichtbarkeit usw.) bieten. 3) Die derzeitige Praxis (z. B. die Verwendung von POST in RPC-Spezifikationen) übertrifft Definitionalisten, die ihre eigenen API-Regeln erstellen. 4) REST erfordert eine einheitliche Schnittstelle (gemäß der HTTP-Spezifikation).
Raymond Hettinger

@Kirk was denkst du über die neuen Antworten? Gibt es etwas, das Sie noch wissen möchten, das aber in keinem von ihnen angesprochen wurde? Gerne bearbeite ich meine Antwort erneut, wenn sie hilfreicher sein kann.
Jordanien

@ RaymondHettinger PATCHkann angemessen sein. Ich erkläre gegen Ende meiner Antwort , warum .
Jordanien

PATCH ist nur geeignet, um den dog.barkCount um eins zu erhöhen . POST ist die Methode zum Senden von E-Mails, Erstellen eines neuen Bark-Datensatzes, Ausführen von Befehlen zum Herunterladen von Github oder Auslösen einer Textnachricht. @Jordan, Ihre Lektüre des PATCH RFC ist einfallsreich, widerspricht jedoch etwas seiner Absicht als Variante des PUT zur teilweisen Änderung von Ressourcen. Ich glaube nicht, dass Sie dem OP helfen, indem Sie unkonventionelle Messwerte der HTTP-Spezifikationen liefern, anstatt die Standardpraxis der Verwendung von POST für Remoteprozeduraufrufe anzuerkennen.
Raymond Hettinger

@RaymondHettinger, dessen Praxis de facto POST standardisiert? Alle Standard-RPC-Schnittstellen, die ich gesehen habe, identifizieren eine Ressource nach Entität (nicht RESTful) im Vergleich zum URI. Daher muss eine gültige Antwort, die die RPC-Konvention priorisiert, ohnehin unkonventionell sein, was meiner Meinung nach den Wert herkömmlicher RPC widerlegt: Eine ist einfallsreich oder inkonsistent . Mit POST können Sie nichts falsch machen, da es das Allheilmittel für die Datenverarbeitung ist. Es gibt jedoch spezifischere Methoden. REST bedeutet, Ressourcen zu benennen und Änderungen in ihrem Status zu beschreiben, nicht Prozeduren zum Ändern des Status. PATCH und POST beschreiben beide Statusänderungen.
Jordanien

Antworten:


280

Warum ein RESTful Design anstreben?

Die RESTful-Prinzipien bringen die Funktionen, die es Websites erleichtern (für einen zufälligen menschlichen Benutzer, sie zu "surfen"), in das API-Design der Webdienste ein , sodass sie für einen Programmierer einfach zu verwenden sind. REST ist nicht gut, weil es REST ist, es ist gut, weil es gut ist. Und es ist vor allem deshalb gut, weil es einfach ist .

Die Einfachheit von einfachem HTTP (ohne SOAP-Umschläge und überlastete Single-URI- POSTDienste), was manche als "Mangel an Funktionen" bezeichnen , ist tatsächlich seine größte Stärke . HTTP fordert Sie von Anfang an auf Adressierbarkeit und Statuslosigkeit : Die beiden grundlegenden Entwurfsentscheidungen, mit denen HTTP auf die heutigen Mega-Sites (und Mega-Services) skalierbar bleibt.

Aber REST ist nicht das Beste: Manchmal kann ein RPC-Stil ("Remote Procedure Call" - wie SOAP) angebracht sein , und manchmal haben andere Anforderungen Vorrang vor den Vorzügen des Web. Das ist in Ordnung. Was wir nicht wirklich mögen, ist unnötige Komplexität . Zu oft bringt ein Programmierer oder ein Unternehmen RPC-ähnliche Dienste für einen Job ein, den einfaches altes HTTP problemlos verarbeiten kann. Der Effekt ist, dass HTTP für eine enorme XML-Nutzlast auf ein Transportprotokoll reduziert wird, das erklärt, was "wirklich" vor sich geht (nicht der URI oder die HTTP-Methode geben einen Hinweis darauf). Der resultierende Service ist viel zu komplex, kann nicht debuggt werden und funktioniert nur, wenn Ihre Clients genau das Setup haben, das der Entwickler beabsichtigt hat.

Ebenso wie ein Java / C # -Code nicht objektorientiert sein kann, macht die Verwendung von HTTP ein Design nicht RESTful. Man kann in der Eile gefangen sein, über ihre Dienste in Bezug auf Aktionen und entfernte Methoden nachzudenken , die aufgerufen werden sollten. Kein Wunder, dass dies meistens in einem RPC-Dienst (oder einem REST-RPC-Hybrid) endet. Der erste Schritt ist, anders zu denken. Ein RESTful-Design kann auf viele Arten erreicht werden. Eine Möglichkeit besteht darin , Ihre Anwendung in Bezug auf Ressourcen und nicht in Bezug auf Aktionen zu betrachten:

💡 Anstatt in Aktionen zu denken, die es ausführen kann ("Suche nach Orten auf der Karte") ...

... versuchen, in den Ergebnissen dieser Aktionen zu denken ("die Liste der Orte auf der Karte, die einem Suchkriterium entsprechen").

Ich werde unten Beispiele anführen. (Ein weiterer wichtiger Aspekt von REST ist die Verwendung von HATEOAS - ich putze es hier nicht, aber ich spreche in einem anderen Beitrag schnell darüber .)


Probleme des ersten Entwurfs

Werfen wir einen Blick auf das vorgeschlagene Design:

ACTION http://api.animals.com/v1/dogs/1/

Zunächst sollten wir nicht in Betracht ziehen, ein neues HTTP-Verb ( ACTION) zu erstellen . Im Allgemeinen ist dies aus mehreren Gründen unerwünscht :

  • (1) Woher weiß ein "zufälliger" Programmierer, wenn nur die Service-URI angegeben ist, dass das ACTIONVerb existiert?
  • (2) Wenn der Programmierer weiß, dass es existiert, wie wird er seine Semantik kennen? Was bedeutet dieses Verb?
  • (3) Welche Eigenschaften (Sicherheit, Idempotenz) sollte man von diesem Verb erwarten?
  • (4) Was ist, wenn der Programmierer einen sehr einfachen Client hat, der nur Standard-HTTP-Verben verarbeitet?
  • (5) ...

Lassen Sie uns nun die Verwendung in Betracht ziehenPOST (ich werde unten diskutieren, warum, nehmen Sie jetzt einfach mein Wort dafür):

POST /v1/dogs/1/ HTTP/1.1
Host: api.animals.com

{"action":"bark"}

Dies könnte in Ordnung sein ... aber nur wenn :

  • {"action":"bark"}war ein Dokument; und
  • /v1/dogs/1/war ein "Dokumentenprozessor" (werkseitig) URI. Ein "Dokumentprozessor" ist eine URI, auf die Sie nur "werfen" und "vergessen" würden. Der Prozessor leitet Sie möglicherweise nach dem "Werfen" zu einer neu erstellten Ressource weiter. Beispiel: Der URI zum Posten von Nachrichten bei einem Nachrichtenbrokerdienst, der Sie nach dem Posten zu einem URI umleitet, der den Status der Nachrichtenverarbeitung anzeigt.

Ich weiß nicht viel über Ihr System, aber ich würde bereits wetten, dass beide nicht wahr sind:

  • {"action":"bark"} ist kein Dokument , sondern die Methode, mit der Sie versuchen, sich in den Dienst einzuschleichen. und
  • Die /v1/dogs/1/URI stellt eine "Hund" -Ressource dar (wahrscheinlich der Hund mit id==1) und kein Dokumentenprozessor.

Alles was wir jetzt wissen ist, dass das obige Design nicht so RESTful ist, aber was ist das genau? Was ist daran so schlimm? Grundsätzlich ist es schlecht, weil das eine komplexe URI mit komplexen Bedeutungen ist. Daraus kann man nichts schließen. Wie würde ein Programmierer wissen, dass ein Hund eine barkAktion hat, die heimlich mit einem infundiert POSTwerden kann?


Entwerfen der API-Aufrufe Ihrer Frage

Kommen wir also zur Sache und versuchen, diese Rinden RESTful zu gestalten, indem wir in Ressourcen denken . Gestatten Sie mir, das Buch Restful Web Services zu zitieren :

Eine POSTAnforderung ist ein Versuch, eine neue Ressource aus einer vorhandenen zu erstellen. Die vorhandene Ressource kann im Sinne einer Datenstruktur die übergeordnete Ressource der neuen Ressource sein, so wie die Wurzel eines Baums die übergeordnete Ressource aller seiner Blattknoten ist. Oder die vorhandene Ressource kann eine spezielle "Fabrik" -Ressource sein, deren einziger Zweck darin besteht, andere Ressourcen zu generieren. Die zusammen mit einer POSTAnforderung gesendete Darstellung beschreibt den Anfangszustand der neuen Ressource. Wie bei PUT muss eine POSTAnfrage überhaupt keine Darstellung enthalten.

Nach der obigen Beschreibung können wir sehen, dass barkdies als Unterressource von adog modelliert werden kann (da a barkin einem Hund enthalten ist, dh eine Rinde von einem Hund "gebellt" wird ).

Aus dieser Überlegung haben wir bereits:

  • Die Methode ist POST
  • Die Ressource ist /barksSubressource of Dog : /v1/dogs/1/barks, repräsentiert eine bark"Fabrik". Diese URI ist für jeden Hund eindeutig (da sie unter ist /v1/dogs/{id}).

Jetzt hat jeder Fall Ihrer Liste ein bestimmtes Verhalten.

1. bark sendet einfach eine E-Mail an dog.emailund zeichnet nichts auf.

Ist das Bellen (Senden einer E-Mail) eine synchrone oder asynchrone Aufgabe? Zweitens erfordert die barkAnfrage ein Dokument (möglicherweise die E-Mail) oder ist es leer?


1.1 Rinde sendet eine E-Mail an dog.emailund zeichnet nichts auf (als synchrone Aufgabe)

Dieser Fall ist einfach. Ein Anruf bei der barksWerksressource führt sofort zu einer Rinde (einer gesendeten E-Mail) und die Antwort (ob OK oder nicht) wird sofort gegeben:

POST /v1/dogs/1/barks HTTP/1.1
Host: api.animals.com
Authorization: Basic mAUhhuE08u724bh249a2xaP=

(entity-body is empty - or, if you require a **document**, place it here)

200 OK

Da es nichts aufzeichnet (ändert), 200 OKist genug. Es zeigt, dass alles wie erwartet gelaufen ist.


1.2 bark sendet eine E-Mail an dog.emailund zeichnet nichts auf (als asynchrone Aufgabe)

In diesem Fall muss der Client eine Möglichkeit haben, die barkAufgabe zu verfolgen . Die barkAufgabe sollte dann eine Ressource mit einer eigenen URI sein:

POST /v1/dogs/1/barks HTTP/1.1
Host: api.animals.com
Authorization: Basic mAUhhuE08u724bh249a2xaP=

{document body, if needed;
NOTE: when possible, the response SHOULD contain a short hypertext note with a hyperlink
to the newly created resource (bark) URI, the same returned in the Location header
(also notice that, for the 202 status code, the Location header meaning is not
standardized, thus the importance of a hipertext/hyperlink response)}

202 Accepted
Location: http://api.animals.com/v1/dogs/1/barks/a65h44

Auf diese Weise ist jeder barknachvollziehbar. Der Client kann dann eine GETan die barkURI senden, um den aktuellen Status zu ermitteln. Vielleicht sogar ein verwenden DELETE, um es abzubrechen.


2. bark sendet eine E-Mail an dog.emailund erhöht sich dann dog.barkCountum 1

Dies kann schwieriger sein, wenn Sie dem Client mitteilen möchten, dass die dogRessource geändert wird:

POST /v1/dogs/1/barks HTTP/1.1
Host: api.animals.com
Authorization: Basic mAUhhuE08u724bh249a2xaP=

{document body, if needed; when possible, containing a hipertext/hyperlink with the address
in the Location header -- says the standard}

303 See Other
Location: http://api.animals.com/v1/dogs/1

In diesem Fall soll der locationHeader den Client wissen lassen, dass er einen Blick darauf werfen soll dog. Aus dem HTTP-RFC über303 :

Diese Methode dient hauptsächlich dazu, dass die Ausgabe eines POSTaktivierten Skripts den Benutzeragenten zu einer ausgewählten Ressource umleitet.

Wenn die Aufgabe asynchron ist, barkwird genau wie in der 1.2Situation eine Unterressource benötigt, 303die nach Abschluss GET .../barks/Yder Aufgabe zurückgegeben werden sollte.


3. Rinde erstellt einen neuen " bark" Datensatz mit bark.timestampAufzeichnung, wenn die Rinde aufgetreten ist. Es wird auch dog.barkCountum 1 erhöht .

POST /v1/dogs/1/barks HTTP/1.1
Host: api.animals.com
Authorization: Basic mAUhhuE08u724bh249a2xaP=

(document body, if needed)

201 Created
Location: http://api.animals.com/v1/dogs/1/barks/a65h44

Hier barkwird das aufgrund der Anforderung erstellt, sodass der Status 201 Createdangewendet wird.

Wenn die Erstellung asynchron ist, 202 Acceptedist stattdessen a erforderlich ( wie im HTTP-RFC angegeben ).

Der gespeicherte Zeitstempel ist Teil der barkRessource und kann mit einem darauf abgerufen werden GET. Der aktualisierte Hund kann auch darin "dokumentiert" werden GET dogs/X/barks/Y.


4. bark führt einen Systembefehl aus, um die neueste Version des Hundecodes von Github abzurufen. Anschließend wird eine Textnachricht gesendet, in dog.ownerder ihnen mitgeteilt wird, dass der neue Hundecode in Produktion ist.

Der Wortlaut dieses Artikels ist kompliziert, aber es ist so ziemlich eine einfache asynchrone Aufgabe:

POST /v1/dogs/1/barks HTTP/1.1
Host: api.animals.com
Authorization: Basic mAUhhuE08u724bh249a2xaP=

(document body, if needed)

202 Accepted
Location: http://api.animals.com/v1/dogs/1/barks/a65h44

Der Client würde dann GETs ausgeben /v1/dogs/1/barks/a65h44, um den aktuellen Status zu erfahren (wenn der Code abgerufen wurde, wurde die E-Mail an den Eigentümer gesendet und so weiter). Wann immer sich der Hund ändert, 303ist a anwendbar.


Einpacken

Zitat von Roy Fielding :

Das einzige, was REST von Methoden verlangt, ist, dass sie für alle Ressourcen einheitlich definiert sind (dh dass Vermittler den Ressourcentyp nicht kennen müssen, um die Bedeutung der Anforderung zu verstehen).

In den obigen Beispielen POSTist einheitlich ausgelegt. Es wird den Hund " bark" machen. Das ist weder sicher (was bedeutet, dass Rinde Auswirkungen auf die Ressourcen hat) noch idempotent (jede Anfrage ergibt eine neue bark), was gut zum POSTVerb passt .

Ein Programmierer würde wissen: a, POSTum a zu barksergeben bark. Die Antwortstatuscodes (bei Bedarf auch mit Entity-Body und Headern) erläutern, was sich geändert hat und wie der Client vorgehen kann und sollte.

Hinweis: Die wichtigsten verwendeten Quellen waren: " Restful Web Services " -Buch, HTTP RFC und Roy Fieldings Blog .




Bearbeiten:

Die Frage und damit die Antwort haben sich seit ihrer Erstellung erheblich geändert. Die ursprüngliche Frage zum Design einer URI lautet wie folgt:

ACTION http://api.animals.com/v1/dogs/1/?action=bark

Nachfolgend finden Sie eine Erklärung, warum dies keine gute Wahl ist:

Wie Clients dem Server mitteilen, was mit den Daten zu tun ist, sind die Methodeninformationen .

  • RESTful-Webdienste übertragen Methodeninformationen in der HTTP-Methode.
  • Typische RPC-Style- und SOAP-Services behalten ihre im Entity-Body und im HTTP-Header.

Welcher Teil der Daten [der Client möchte, dass der Server] bearbeitet wird, sind die Scoping-Informationen .

  • RESTful-Services verwenden den URI. SOAP / RPC-artige Dienste verwenden erneut die Entity-Body- und HTTP-Header.

Nehmen Sie als Beispiel den URI von Google http://www.google.com/search?q=DOG. Dort sind die Methodeninformationen GETund die Scoping-Informationen /search?q=DOG.

Um es kurz zu machen:

  • In RESTful-Architekturen gehen die Methodeninformationen in die HTTP-Methode ein.
  • In ressourcenorientierten Architekturen werden die Bereichsinformationen in die URI eingegeben.

Und die Faustregel:

Wenn die HTTP-Methode nicht mit den Methodeninformationen übereinstimmt, ist der Dienst nicht RESTful. Wenn sich die Scoping-Informationen nicht in der URI befinden, ist der Service nicht ressourcenorientiert.

Sie können die "Rinde" "Aktion" in die URL (oder in den Entity-Body) einfügen und verwenden POST. Kein Problem, es funktioniert und ist vielleicht der einfachste Weg, dies zu tun, aber dies ist nicht RESTful .

Um Ihren Service wirklich RESTful zu halten, müssen Sie möglicherweise einen Schritt zurücktreten und überlegen, was Sie hier wirklich tun möchten (welche Auswirkungen dies auf die Ressourcen haben wird).

Ich kann nicht über Ihre spezifischen Geschäftsanforderungen sprechen, aber ich möchte Ihnen ein Beispiel geben: Betrachten Sie einen RESTful-Bestellservice, bei dem Bestellungen wie bei URIs erfolgen example.com/order/123.

Angenommen, wir möchten eine Bestellung stornieren. Wie machen wir das? Man könnte versucht sein zu glauben, dass dies eine "Stornierung", "Aktion" ist, und sie als zu gestalten POST example.com/order/123?do=cancel.

Das ist nicht RESTful, wie wir oben gesprochen haben. Stattdessen könnten wir PUTeine neue Darstellung von ordermit einem canceledElement senden, das an truefolgende Adresse gesendet wird :

PUT /order/123 HTTP/1.1
Content-Type: application/xml

<order id="123">
    <customer id="89987">...</customer>
    <canceled>true</canceled>
    ...
</order>

Und das ist es. Wenn die Bestellung nicht storniert werden kann, kann ein bestimmter Statuscode zurückgegeben werden. (Der Einfachheit halber kann auch ein Subressourcen-Design wie POST /order/123/canceledbeim Entity-Body trueverfügbar sein.)

In Ihrem speziellen Szenario können Sie etwas Ähnliches ausprobieren. Auf diese Weise könnte ein GETat , während beispielsweise ein Hund bellt, /v1/dogs/1/diese Informationen enthalten (z<barking>true</barking> . B. ) . Oder ... wenn das zu kompliziert ist, lockern Sie Ihre RESTful-Anforderung und bleiben Sie dabei POST.

Aktualisieren:

Ich möchte die Antwort nicht zu groß machen, aber es dauert eine Weile, bis ich den Dreh raus habe, einen Algorithmus (eine Aktion ) als eine Reihe von Ressourcen verfügbar zu machen. Anstatt in Aktionen zu denken ( "Suche nach Orten auf der Karte" ), muss man in den Ergebnissen dieser Aktion denken ( "die Liste der Orte auf der Karte, die einem Suchkriterium entsprechen" ).

Möglicherweise kehren Sie zu diesem Schritt zurück, wenn Sie feststellen, dass Ihr Design nicht zur einheitlichen HTTP-Oberfläche passt.

Query - Variablen sind Scoping Informationen , aber nicht bezeichnen neue Ressourcen ( /post?lang=enist eindeutig die gleiche Ressource wie /post?lang=jp, nur eine andere Darstellung). Sie werden vielmehr verwendet, um den Client-Status (z. B. ?page=10damit der Status nicht auf dem Server gespeichert wird; dies ?lang=enist auch hier ein Beispiel) oder Eingabeparameter für algorithmische Ressourcen ( /search?q=dogs, /dogs?code=1) zu übermitteln . Wieder keine unterschiedlichen Ressourcen.

Eigenschaften von HTTP-Verben (Methoden):

Ein weiterer klarer Punkt, der ?action=somethingin der URI angezeigt wird, ist nicht RESTful. Dies sind die Eigenschaften von HTTP-Verben:

  • GETund HEADsind sicher (und idempotent);
  • PUTund DELETEsind nur idempotent;
  • POST ist weder.

Sicherheit : Eine GEToder HEADAnforderung ist eine Anforderung zum Lesen einiger Daten, keine Anforderung zum Ändern eines Serverstatus. Der Client kann 10 Mal eine GEToder eine HEADAnfrage stellen, und es ist dasselbe wie einmal oder gar nicht .

Idempotenz : Eine idempotente Operation in einer, die den gleichen Effekt hat, unabhängig davon, ob Sie sie einmal oder mehrmals anwenden (in der Mathematik ist das Multiplizieren mit Null idempotent). Wenn Sie DELETEeine Ressource einmal haben, hat das erneute Löschen den gleichen Effekt (die Ressource ist GONEbereits vorhanden).

POSTist weder sicher noch idempotent. Wenn Sie zwei identische POSTAnforderungen an eine 'Factory'-Ressource stellen, werden wahrscheinlich zwei untergeordnete Ressourcen dieselbe Information enthalten. Bei Überlastung (Methode in URI oder Entity-Body) POSTsind alle Wetten deaktiviert.

Beide Eigenschaften waren wichtig für den Erfolg des HTTP-Protokolls (über unzuverlässige Netzwerke!): Wie oft haben Sie GETdie Seite aktualisiert ( ), ohne zu warten, bis sie vollständig geladen ist?

Das Erstellen und Einfügen einer Aktion in die URL bricht eindeutig den Vertrag der HTTP-Methoden. Die Technologie ermöglicht es Ihnen erneut, dies zu tun, aber das ist kein RESTful-Design.


Ich bezweifle, dass das Aufrufen einer Aktion auf einem Server, der in der URL als Aktion festgelegt ist, nicht RESTful ist. POSTwurde entwickelt, um "einen Datenblock ... für einen Datenverarbeitungsprozess bereitzustellen" . Es scheint, dass viele Leute Ressourcen von Aktionen unterscheiden, aber tatsächlich sind Aktionen nur eine Art von Ressource.
Jacob Stevens

1
@JacobStevens Das OP hat die Frage ein wenig geändert, daher muss ich meine Antwort aktualisieren, um sie direkter zu gestalten (überprüfen Sie die ursprüngliche Frage , vielleicht werden Sie sehen, was ich meine). Ich stimme mit POST„einen Block von Daten ... zu einer Datenverarbeitungsprozess bereitstellt“, aber der Unterschied ist wirklich , dass ein Block von Daten , nicht ein Block von Daten und die Prozedur (Aktion, Verfahren, Befehl) zu sein dann ausgeführt. Das ist POSTÜberladung, und POSTÜberladung ist RPC-artiges Design, nicht RESTful.
Acdcjunior

Ich gehe davon aus, dass die Aktions- / Methodenlogik auf dem Server gespeichert ist. Was wäre sonst der Zweck des Aufrufs? In dem Fall, den Sie beschreiben, stimme ich zu, wäre das kein gutes Design. Die Methode oder Unterroutine, die die Aktion ausführt, wird jedoch vom URI angegeben (ein weiterer Grund, warum eine als Verb am Ende einer URL festgelegte Aktionsressource nützlich und REST-fähig ist, obwohl viele davon abraten).
Jacob Stevens

6
Die Antwort hat uns aktualisiert. Es ist ein bisschen lang, weil eine gründliche Erklärung notwendig schien ("Denken Sie daran, ich habe ein rudimentäres Verständnis von REST."). Es war eine Art Kampf, es so klar wie möglich zu machen. Hoffe, es ist irgendwie nützlich.
Acdcjunior

2
Tolle Erklärung, ich habe abgestimmt, aber der Location-Header sollte nicht in 202 Accepted Response verwendet werden. Es scheint eine falsche Interpretation zu sein, die viele Leute von RFC machen. Überprüfen Sie diese stackoverflow.com/questions/26199228/…
Delmo

6

Ich habe früher geantwortet , aber diese Antwort widerspricht meiner alten Antwort und verfolgt eine ganz andere Strategie, um zu einer Lösung zu kommen. Es zeigt, wie die HTTP-Anforderung aus den Konzepten erstellt wird, die REST und HTTP definieren. Es wird auch PATCHanstelle von POSToder verwendet PUT.

Es geht durch die REST-Einschränkungen, dann die Komponenten von HTTP, dann eine mögliche Lösung.

SICH AUSRUHEN

REST ist eine Reihe von Einschränkungen, die auf ein verteiltes Hypermedia-System angewendet werden sollen, um es skalierbar zu machen. Selbst um dies im Zusammenhang mit der Fernsteuerung einer Aktion zu verstehen, müssen Sie sich vorstellen, eine Aktion als Teil eines verteilten Hypermedia-Systems fernzusteuern - als Teil eines Systems zum Erkennen, Anzeigen und Ändern miteinander verbundener Informationen. Wenn das mehr Ärger ist als es wert ist, dann ist es wahrscheinlich nicht gut zu versuchen, es RESTful zu machen. Wenn Sie nur eine GUI vom Typ "Control Panel" auf dem Client möchten, die über Port 80 Aktionen auf dem Server auslösen kann, möchten Sie wahrscheinlich eine einfache RPC-Schnittstelle wie JSON-RPC über HTTP-Anforderungen / -Antworten oder einen WebSocket.

Aber REST ist eine faszinierende Denkweise und das Beispiel in der Frage ist einfach mit einer RESTful-Oberfläche zu modellieren. Nehmen wir also die Herausforderung zum Spaß und zur Bildung an.

REST wird durch vier Schnittstellenbeschränkungen definiert :

Identifizierung von Ressourcen; Manipulation von Ressourcen durch Repräsentationen; selbstbeschreibende Nachrichten; und Hypermedia als Motor des Anwendungsstatus.

Sie fragen, wie Sie eine Schnittstelle definieren können, die diese Einschränkungen erfüllt und über die ein Computer einen anderen Computer anweist, einen Hund bellen zu lassen. Insbesondere möchten Sie, dass Ihre Schnittstelle HTTP ist, und Sie möchten nicht die Funktionen verwerfen, die HTTP bei bestimmungsgemäßer Verwendung RESTful machen.

Beginnen wir mit der ersten Einschränkung: Ressourcenidentifikation .

Alle Informationen, die benannt werden können, können eine Ressource sein: ein Dokument oder Bild, ein zeitlicher Dienst (z. B. "heutiges Wetter in Los Angeles"), eine Sammlung anderer Ressourcen, ein nicht virtuelles Objekt (z. B. eine Person) usw. .

Ein Hund ist also eine Ressource. Es muss identifiziert werden.

Genauer gesagt ist eine Ressource R eine zeitlich variierende Zugehörigkeitsfunktion M R ( t ), die für die Zeit t einer Menge von Entitäten oder Werten zugeordnet ist, die äquivalent sind. Die Werte in der Menge können Ressourcendarstellungen und / oder Ressourcenkennungen sein .

Sie modellieren einen Hund, indem Sie eine Reihe von Kennungen und Darstellungen nehmen und sagen, dass sie alle zu einem bestimmten Zeitpunkt miteinander verbunden sind. Verwenden wir zunächst die Kennung "Hund Nr. 1". Das bringt uns zu der zweiten und dritten Einschränkung: Ressourcendarstellung und Selbstbeschreibung .

REST-Komponenten führen Aktionen für eine Ressource aus, indem sie mithilfe einer Darstellung den aktuellen oder beabsichtigten Status dieser Ressource erfassen und diese Darstellung zwischen Komponenten übertragen. Eine Darstellung ist eine Folge von Bytes plus Darstellungsmetadaten zur Beschreibung dieser Bytes.

Es folgt eine Folge von Bytes, die den beabsichtigten Zustand des Hundes erfassen, dh die Darstellung, die wir mit der Kennung "Hund Nr. 1" verknüpfen möchten (beachten Sie, dass sie nur einen Teil des Zustands darstellt, da der Name und die Gesundheit des Hundes nicht berücksichtigt werden oder sogar vergangene Rinden):

Seit dieser Zustandsänderung hat es alle 10 Minuten gebellt und wird auf unbestimmte Zeit fortgesetzt.

Es soll an Metadaten angehängt werden, die es beschreiben. Diese Metadaten könnten nützlich sein:

Es ist eine englische Aussage. Es beschreibt einen Teil des beabsichtigten Zustands. Wenn es mehrmals empfangen wird, lassen Sie nur das erste eine Wirkung haben.

Schauen wir uns zum Schluss die vierte Einschränkung an: HATEOAS .

REST ... betrachtet eine Anwendung als eine zusammenhängende Struktur von Informations- und Steuerungsalternativen, über die ein Benutzer eine gewünschte Aufgabe ausführen kann. Das Nachschlagen eines Wortes in einem Online-Wörterbuch ist beispielsweise eine Anwendung, ebenso wie das Durchlaufen eines virtuellen Museums oder das Überprüfen einer Reihe von Notizen, um für eine Prüfung zu lernen. ... Der nächste Steuerungsstatus einer Anwendung befindet sich in der Darstellung der ersten angeforderten Ressource, sodass das Erhalten dieser ersten Darstellung Priorität hat. ... Die Modellanwendung ist daher eine Engine, die von einem Zustand zum nächsten wechselt, indem sie die alternativen Zustandsübergänge in der aktuellen Reihe von Darstellungen untersucht und aus ihnen auswählt.

In einer RESTful-Schnittstelle erhält der Client eine Ressourcendarstellung, um herauszufinden, wie er eine Darstellung empfangen oder senden soll. Irgendwo in der Anwendung muss eine Darstellung vorhanden sein, von der der Client herausfinden kann, wie er alle Darstellungen empfangen oder senden kann, die er empfangen oder senden kann, selbst wenn er einer Kette von Darstellungen folgt, um zu diesen Informationen zu gelangen. Das scheint einfach zu sein:

Der Client fordert eine Darstellung einer als Homepage identifizierten Ressource an. Als Antwort erhält es eine Darstellung, die eine Kennung jedes Hundes enthält, den der Kunde möglicherweise möchte. Der Kunde extrahiert eine Kennung daraus und fragt den Dienst, wie er mit dem identifizierten Hund interagieren kann. Der Dienst sagt, dass der Kunde eine englische Erklärung senden kann, die einen Teil des beabsichtigten Zustands des Hundes beschreibt. Dann sendet der Client eine solche Anweisung und empfängt eine Erfolgsmeldung oder eine Fehlermeldung.

HTTP

HTTP implementiert REST-Einschränkungen wie folgt:

Ressourcenidentifikation : URI

Ressourcendarstellung : Entity-Body

Selbstbeschreibung : Methoden- oder Statuscode, Header und möglicherweise Teile des Entitätskörpers (z. B. der URI eines XML-Schemas)

HATEOAS : Hyperlinks

Sie haben sich http://api.animals.com/v1/dogs/1als URI entschieden. Nehmen wir an, der Client hat dies von einer Seite auf der Site erhalten.

Verwenden wir diesen Entitätskörper (der Wert von nextist ein Zeitstempel; ein Wert von 0bedeutet "wenn diese Anforderung empfangen wird"):

{"barks": {"next": 0, "frequency": 10}}

Jetzt brauchen wir eine Methode. PATCH passt zu der Beschreibung "Teil des beabsichtigten Zustands", für die wir uns entschieden haben:

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

Und einige Überschriften:

So geben Sie die Sprache des Entitätskörpers an: Content-Type: application/json

Um sicherzustellen, dass es nur einmal passiert: If-Unmodified-Since: <date/time this was first sent>

Und wir haben eine Anfrage:

PATCH /v1/dogs/1/ HTTP/1.1
Host: api.animals.com
Content-Type: application/json
If-Unmodified-Since: <date/time this was first sent>
[other headers]

{"barks": {"next": 0, "frequency": 10}}

Bei Erfolg sollte der Kunde als 204Antwort einen Statuscode erhalten oder eine, 205wenn sich die Darstellung von /v1/dogs/1/geändert hat, um den neuen Bellenplan widerzuspiegeln.

Bei einem Fehler sollte eine 403und eine hilfreiche Meldung angezeigt werden, warum.

Für REST ist es nicht unbedingt erforderlich, dass der Service den Rindenplan in einer Darstellung als Antwort auf widerspiegelt GET /v1/dogs/1/, aber es wäre am sinnvollsten, wenn eine JSON-Darstellung Folgendes enthalten würde:

"barks": {
    "previous": [x_1, x_2, ..., x_n],
    "next": x_n,
    "frequency": 10
}

Behandeln Sie den Cron-Job als Implementierungsdetail, das der Server vor der Schnittstelle verbirgt. Das ist das Schöne an einer generischen Benutzeroberfläche. Der Client muss nicht wissen, was der Server hinter den Kulissen tut. Alles, was es interessiert, ist, dass der Dienst angeforderte Statusänderungen versteht und darauf reagiert.


3

Die meisten Leute benutzen POST für diesen Zweck. Es ist geeignet, um "unsichere oder nicht epidempotente Operationen durchzuführen, wenn keine andere HTTP-Methode angemessen erscheint".

APIs wie XMLRPC verwenden POST , um Aktionen auszulösen, mit denen beliebiger Code ausgeführt werden kann. Die "Aktion" ist in den POST-Daten enthalten:

POST /RPC2 HTTP/1.0
User-Agent: Frontier/5.1.2 (WinNT)
Host: betty.userland.com
Content-Type: text/xml
Content-length: 181

<?xml version="1.0"?>
<methodCall>
   <methodName>examples.getStateName</methodName>
   <params>
      <param>
         <value><i4>41</i4></value>
         </param>
      </params>
   </methodCall>

Das RPC-Beispiel soll zeigen, dass POST die herkömmliche Wahl von HTTP-Verben für serverseitige Methoden ist. Hier sind Roy Fieldings Gedanken zu POST - er sagt ziemlich genau, dass es RESTful ist, die angegebenen HTTP-Methoden zu verwenden.

Beachten Sie, dass RPC selbst nicht sehr REST-fähig ist, da es nicht ressourcenorientiert ist. Wenn Sie jedoch Staatenlosigkeit, Caching oder Layering benötigen, ist es nicht schwer, die entsprechenden Transformationen vorzunehmen. Ein Beispiel finden Sie unter http://blog.perfectapi.com/2012/opinionated-rpc-apis-vs-restful-apis/ .


Ich denke, Sie würden die Parameter per URL codieren, ohne sie in die Abfragezeichenfolge einzufügen
tacos_tacos_tacos

@ Kirk Ja, aber mit einer geringfügigen Änderung lassen Sie den letzten Schrägstrich fallen: POST api.animals.com/v1/dogs1?action=bark
Raymond Hettinger

Wenn Sie den Ratschlägen in dieser Antwort folgen, denken Sie daran, dass die resultierende API nicht RESTful ist.
Nicholas Shanks

2
Dies ist nicht RESTful, da HTTP die URL als Kennung einer Ressource festlegt und eine URL von /RPC2nichts zur Identifizierung einer Ressource beiträgt - sie identifiziert eine Servertechnologie. Stattdessen wird methodNameversucht, die 'Ressource' zu 'identifizieren' - aber selbst dann profitiert es nicht von der Unterscheidung zwischen Substantiv und Verb. Das einzige, was hier wie ein Verb aussieht, ist methodCall. Dies ist wie "Statusnamen abrufen" anstelle von "Statusnamen abrufen" - letzteres ist viel sinnvoller.
Jordanien

+1 für die Links; sehr informativ und das "Opinioned RPC" -Experiment ist erfinderisch.
Jordanien

2

POSTist die HTTP-Methode für

Bereitstellen eines Datenblocks ... für einen Datenverarbeitungsprozess

Serverseitige Methoden, die nicht CRUD-zugeordnete Aktionen verarbeiten, sind das, was Roy Fielding mit REST beabsichtigt hat. Sie sind also gut darin, und deshalb POSTwurde es so gemacht, dass es nicht idempotent ist. POSTbehandelt die meisten Daten an serverseitige Methoden, um die Informationen zu verarbeiten.

Das heißt, wenn Sie in Ihrem Szenario mit Hundebellen alle 10 Minuten ein serverseitiges Bellen durchführen möchten, aber aus irgendeinem Grund der Auslöser von einem Client stammen muss, PUTwürde dies aufgrund seiner Idempotenz den Zweck besser erfüllen. Genau genommen besteht in diesem Szenario kein offensichtliches Risiko, dass mehrere POST-Anfragen dazu führen, dass Ihr Hund stattdessen miaut, aber das ist trotzdem der Zweck der beiden ähnlichen Methoden. Meine Antwort auf eine ähnliche SO-Frage kann für Sie nützlich sein.


1
Bei PUT vs. POST dreht sich alles um die URL. Der dritte Absatz nach 9,6 PUT sagt der Zweck der beiden Methoden ist , so dass die PUTURL bezieht sich auf das, was sollte werden ersetzt durch die Client-Inhalt und die POSTURL verweist auf das, was sollte verarbeiten des Kunden Inhalt aber es will.
Jordanien

1

Wenn wir annehmen, dass Barking eine innere / abhängige / untergeordnete Ressource ist, auf die der Verbraucher reagieren kann, können wir sagen:

POST http://api.animals.com/v1/dogs/1/bark

Hund Nummer 1 bellt

GET http://api.animals.com/v1/dogs/1/bark

Gibt den letzten Rindenzeitstempel zurück

DELETE http://api.animals.com/v1/dogs/1/bark

trifft nicht zu! Also ignoriere es.


Dies ist nur dann RESTful, wenn Sie /v1/dogs/1/barkeine Ressource an sich betrachten und POSTbeschreiben, wie sich der interne Status dieser Ressource ändern sollte. Ich finde es sinnvoller, nur /v1/dogs/1/als Ressource zu betrachten und im Entitätskörper anzugeben, dass es bellen sollte.
Jordanien

mmm .. nun, es ist eine Ressource, deren Status Sie ändern können. Weil das Ergebnis der Änderung seines Zustands Rauschen macht, macht es nicht weniger Ressourcen! Sie betrachten Bark als ein Verb (weshalb), deshalb können Sie es nicht als Ressource betrachten. Ich betrachte es als abhängige Ressource, deren Status geändert werden kann, und da sein Status boolesch ist, sehe ich keinen Grund, ihn im Entity-Body zu erwähnen. Das ist nur meine Meinung.
Bolbol

1

Frühere Überarbeitungen einiger Antworten deuteten darauf hin, dass Sie RPC verwenden. Sie müssen nicht auf RPC schauen müssen , wie es ist durchaus möglich , zu tun , was Sie wollen , während Einschränkungen für den Rest haften.

Fügen Sie zunächst keine Aktionsparameter in die URL ein. Die URL definiert, auf was Sie die Aktion anwenden, und Abfrageparameter sind Teil der URL. Es sollte ganz als Substantiv betrachtet werden. http://api.animals.com/v1/dogs/1/?action=barkist eine andere Ressource - ein anderes Substantiv - zu http://api.animals.com/v1/dogs/1/. [nb Asker hat den ?action=barkURI aus der Frage entfernt.] Vergleichen Sie beispielsweise http://api.animals.com/v1/dogs/?id=1mit http://api.animals.com/v1/dogs/?id=2. Unterschiedliche Ressourcen, die nur durch die Abfragezeichenfolge unterschieden werden. Daher muss die Aktion Ihrer Anfrage im Anfragetext definiert werden, es sei denn, sie entspricht direkt einem körperlosen vorhandenen Methodentyp (TRACE, OPTIONS, HEAD, GET, DELETE usw.).

Entscheiden Sie als Nächstes, ob die Aktion " idempotent " ist, was bedeutet, dass sie ohne nachteilige Auswirkungen wiederholt werden kann (weitere Erläuterungen finden Sie im nächsten Absatz). Das Setzen eines Werts auf true kann beispielsweise wiederholt werden, wenn der Client nicht sicher ist, ob der gewünschte Effekt eingetreten ist. Sie senden die Anfrage erneut und der Wert bleibt wahr. Das Hinzufügen von 1 zu einer Zahl ist nicht idempotent. Wenn der Client den Befehl Add1 sendet, nicht sicher ist, ob er funktioniert hat, und ihn erneut sendet, hat der Server dann einen oder zwei hinzugefügt? Sobald Sie dies festgestellt haben, können Sie besser zwischen PUTund POSTfür Ihre Methode wählen .

Idempotent bedeutet, dass eine Anfrage wiederholt werden kann, ohne das Ergebnis zu ändern. Diese Effekte umfassen nicht die Protokollierung und andere derartige Serveradministrationsaktivitäten. Wenn Sie Ihr erstes und zweites Beispiel verwenden, führt das Senden von zwei E-Mails an dieselbe Person zu einem anderen Status als das Senden einer E-Mail (der Empfänger hat zwei in seinem Posteingang, die er möglicherweise als Spam betrachtet). Daher würde ich POST definitiv dafür verwenden . Wenn der barkCount in Beispiel 2 von einem Benutzer Ihrer API gesehen werden soll oder sich auf etwas auswirkt, das für den Client sichtbar ist, würde dies auch die Anforderung nicht idempotent machen. Wenn es nur von Ihnen angezeigt werden soll, zählt es als Serverprotokollierung und sollte bei der Ermittlung der Idempotenz ignoriert werden.

Stellen Sie abschließend fest, ob die Aktion, die Sie ausführen möchten, sofort erfolgreich sein kann oder nicht. BarkDog ist eine schnell abschließende Aktion. RunMarathon ist nicht. Wenn Ihre Aktion langsam ist, sollten Sie eine 202 Acceptedmit einer URL im Antworttext zurückgeben, die ein Benutzer abfragen kann, um festzustellen, ob die Aktion abgeschlossen ist. Alternativ können Benutzer eine POST an eine Listen-URL wie senden /marathons-in-progress/und diese dann nach Abschluss der Aktion von der URL der laufenden ID zur /marathons-complete/URL umleiten .
Für die speziellen Fälle Nr. 1 und Nr. 2 würde der Server eine Warteschlange hosten und der Client Stapel von Adressen an diese senden. Die Aktion wäre nicht SendEmails, sondern so etwas wie AddToDispatchQueue. Der Server kann dann die Warteschlange abfragen, um festzustellen, ob E-Mail-Adressen warten, und E-Mails senden, wenn er welche findet. Anschließend wird die Warteschlange aktualisiert, um anzuzeigen, dass die ausstehende Aktion jetzt ausgeführt wurde. Sie hätten einen anderen URI, der dem Client den aktuellen Status der Warteschlange anzeigt. Um ein doppeltes Senden von E-Mails zu vermeiden, kann der Server auch ein Protokoll darüber führen, an wen er diese E-Mail gesendet hat, und jede Adresse mit dieser vergleichen, um sicherzustellen, dass niemals zwei an dieselbe Adresse gesendet werden, selbst wenn Sie dieselbe Liste zweimal an POST senden die Warteschlange.

Versuchen Sie bei der Auswahl eines URI für irgendetwas, ihn als Ergebnis und nicht als Aktion zu betrachten. Zum Beispiel google.com/search?q=dogszeigt die Ergebnisse einer Suche nach dem Wort "Hunde". Die Suche muss nicht unbedingt durchgeführt werden.

Die Fälle Nr. 3 und Nr. 4 aus Ihrer Liste sind ebenfalls keine idempotenten Aktionen. Sie schlagen vor, dass die verschiedenen vorgeschlagenen Effekte das API-Design beeinflussen könnten. In allen vier Fällen würde ich dieselbe API verwenden, da alle vier den "Weltzustand" ändern.


Angenommen, die Aktion besteht darin, eine riesige E-Mail-Warteschlange zu durchsuchen und eine Nachricht an eine Gruppe von Personen zu senden. Ist das idempotent? Sind idempotente Aktionen für PUT oder POST?
Kirk Ouimet

@ Kirk Ich habe meine Antwort erweitert.
Nicholas Shanks

0

Siehe meine neue Antwort - sie widerspricht dieser und erklärt REST und HTTP klarer und genauer.

Hier ist eine Empfehlung , die zwar RESTful ist, aber sicherlich nicht die einzige Option ist. So beginnen Sie zu bellen, wenn der Dienst die Anfrage erhält:

POST /v1/dogs/1/bark-schedule HTTP/1.1
...
{"token": 12345, "next": 0, "frequency": 10}

token ist eine beliebige Zahl, die redundantes Bellen verhindert, unabhängig davon, wie oft diese Anforderung gesendet wird.

nextgibt die Zeit der nächsten Rinde an; Ein Wert von 0bedeutet "ASAP".

Jedes Mal , wenn Sie GET /v1/dogs/1/bark-schedule, sollten Sie etwas wie diese erhalten, wo t ist die Zeit der letzten Rinde und u ist t + 10 Minuten:

{"last": t, "next": u}

Ich empfehle dringend, dass Sie dieselbe URL verwenden, um eine Rinde anzufordern, mit der Sie sich über den aktuellen Bellenzustand des Hundes informieren. Für REST ist dies nicht unbedingt erforderlich, es wird jedoch die Änderung des Zeitplans betont.

Der entsprechende Statuscode ist wahrscheinlich 205 . Ich stelle mir einen Client vor, der sich den aktuellen Zeitplan ansieht, POSTdieselbe URL verwendet, um ihn zu ändern, und vom Dienst angewiesen wird, dem Zeitplan einen zweiten Blick zu geben, um zu beweisen, dass er geändert wurde.

Erläuterung

SICH AUSRUHEN

Vergessen Sie für einen Moment HTTP. Es ist wichtig zu verstehen, dass eine Ressource eine Funktion ist, die Zeit als Eingabe benötigt und einen Satz zurückgibt, der Bezeichner und Darstellungen enthält . Vereinfachen wir dies folgendermaßen: Eine Ressource ist eine Menge R von Bezeichnern und Darstellungen; R kann sich ändern - Mitglieder können hinzugefügt, entfernt oder geändert werden. (Obwohl es schlecht ist , instabil Design zu entfernen oder Kennungen zu ändern.) Wir sagen , eine Kennung , die ein Element ist R identifiziert R , und dass eine Darstellung , die ein Element ist R steht für R .

Nehmen wir an, R ist ein Hund. Sie identifizieren R zufällig als /v1/dogs/1. (Bedeutung /v1/dogs/1ist ein Mitglied von R. ) Dies ist nur eine von vielen Möglichkeiten, wie Sie R identifizieren können . Sie können R auch als /v1/dogs/1/x-raysund als identifizieren /v1/rufus.

Wie repräsentieren Sie R ? Vielleicht mit einem Foto. Vielleicht mit einer Reihe von Röntgenstrahlen. Oder vielleicht mit einem Hinweis auf Datum und Uhrzeit, als R zuletzt bellte. Denken Sie jedoch daran, dass dies alles Darstellungen derselben Ressource sind . /v1/dogs/1/x-raysist eine Kennung derselben Ressource, die durch eine Antwort auf die Frage "Wann hat R zuletzt gebellt?" dargestellt wird.

HTTP

Mehrere Darstellungen einer Ressource sind nicht sehr nützlich, wenn Sie sich nicht auf die gewünschte beziehen können. Aus diesem Grund ist HTTP nützlich: Sie können Bezeichner mit Darstellungen verbinden . Das heißt, es ist eine Möglichkeit für den Dienst, eine URL zu erhalten und zu entscheiden, welche Darstellung dem Client bereitgestellt werden soll.

Zumindest ist es das, was es GETtut. PUTist im Grunde das Gegenteil von GET: Sie PUTeine Darstellung r an der URL, wenn Sie möchten, dass zukünftige GETAnforderungen an diese URL r zurückgeben , mit einigen möglichen Übersetzungen wie JSON in HTML.

POSTist eine lockerere Methode zum Ändern einer Darstellung. Stellen Sie sich vor, es gibt Anzeigelogik und Änderungslogik, die einander entgegengesetzt sind - beide entsprechen derselben URL. Eine POST-Anforderung ist eine Anforderung an die Änderungslogik, die Informationen zu verarbeiten und alle Darstellungen (nicht nur die Darstellung, die sich unter derselben URL befindet) nach eigenem Ermessen zu ändern. Beachten Sie den dritten Absatz nach 9.6 PUT : Sie ersetzen das Objekt an der URL nicht durch neuen Inhalt. Sie bitten die Sache unter der URL, einige Informationen zu verarbeiten und intelligent in Form von informativen Darstellungen zu antworten.

In unserem Fall bitten wir die Änderungslogik bei /v1/dogs/1/bark-schedule(die das Gegenstück zur Anzeigelogik ist, die uns sagt, wann sie zuletzt gebellt hat und wann sie das nächste Mal bellt), unsere Informationen zu verarbeiten und einige Darstellungen entsprechend zu ändern. In Reaktion auf zukünftige GETs sagt uns die Anzeigelogik, die derselben URL entspricht, dass der Hund jetzt bellt, wie wir es wünschen.

Stellen Sie sich den Cron-Job als Implementierungsdetail vor. HTTP befasst sich mit dem Anzeigen und Ändern von Darstellungen. Von nun an teilt der Dienst dem Kunden mit, wann der Hund das letzte Mal gebellt hat und wann er das nächste Mal gebellt hat. Aus Sicht des Dienstes ist das ehrlich, denn diese Zeiten entsprechen früheren und geplanten Cron-Jobs.


-1

REST ist ein ressourcenorientierter Standard, es ist nicht handlungsorientiert wie ein RPC.

Wenn Sie möchten, dass Ihr Server bellt , sollten Sie sich mit verschiedenen Ideen wie JSON-RPC oder der Kommunikation mit Websockets befassen.

Jeder Versuch, es RESTful zu halten, schlägt meiner Meinung nach fehl: Sie können einen POSTmit dem actionParameter ausgeben , Sie erstellen keine neuen Ressourcen, aber da Sie möglicherweise Nebenwirkungen haben, sind Sie sicherer.


POSTwurde entwickelt, um "einen Datenblock ... für einen Datenverarbeitungsprozess bereitzustellen" . Es scheint, dass viele Leute Ressourcen von Aktionen unterscheiden, aber tatsächlich sind Aktionen nur eine Art von Ressource. Das Aufrufen einer Aktionsressource auf einem Server ist weiterhin eine einheitliche Schnittstelle, die zwischengespeichert, modular und skalierbar ist. Es ist auch zustandslos, aber das kann verletzt werden, wenn der Client eine Antwort erwartet. Das Aufrufen einer "void-Methode" auf dem Server ist jedoch das, was Roy Fielding mit REST beabsichtigt hat .
Jacob Stevens

Wie ich in meiner Antwort beschreibe , können Sie in REST implizit veranlassen, dass der Server eine Aktion ausführt, indem Sie ihn auffordern, von nun an "Ihre Aktion wurde abgeschlossen" zu sagen, während RPC auf der Idee basiert, nur den Server zur Ausführung aufzufordern die Aktion. Beide sind absolut sinnvoll, ebenso wie die imperative und die deklarative Programmierung sinnvoll sind.
Jordanien
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.