Repräsentiert Aktionen (Verben) in REST-URI

16

Ich muss einen Druckvorgang für meine Kundendokumente ausführen. Ich muss auch die anderen Standardoperationen ausführen, z. B. Hinzufügen, Aktualisieren, Löschen. also habe ich folgendes:

  • Zum Erstellen eines neuen Kunden:
    URI = / customer / {id}, geben Sie = POST, Methodenname = CreateCustomer () ein.
  • Zum Aktualisieren:
    URI: / customer / {id}, Typ = PUT, Methode = UpdateCstomer ()
  • Geben Sie für Kunden
    löschen : URI = / customer / {id} = DELETE, Methodenname = DeleteCustomer () ein.

  • Geben Sie für View: URI: / customer / {id} = GET, method = GetCustomer () ein.

Wenn ich jetzt ein Dokument für diesen Kunden drucken muss, benötige ich eine Druckfunktion. Mein URI könnte folgendermaßen aussehen: / customer / {id}, type = POST, method = PrintCustomer (). Aber ich habe diesen URI- und POST-Typ für CreateCustomer verwendet. Ich wollte, dass der URI so aussieht: / customer / Print / {id}, type = POST, method = PrintCustomer ().

Aber ich kann kein "Print" -Verb in meiner URI haben. Was ist der beste Weg, dies zu tun? Ich dachte an / customer / document / {id} als URI ... aber ich werde auf dasselbe Problem stoßen. Ich hätte die CRUD-Operationen für das "Dokument". Also habe ich wieder nicht mehr das, was ich für "Drucken" verwendet hätte. Bitte beraten.

Nitya Maha
quelle
2
Da das Drucken in der Regel clientseitig erfolgt, bin ich gespannt, wie Ihre Konfiguration dahingehend ist, dass Sie einen Befehl an einen REST-Server senden müssen.
Shauna
2
@Shauna Der URI muss nicht unbedingt eine Anforderung an den Server für eine druckfreundliche Version der Ressource sein (dh eine andere Ansicht).
Evan Plaice
1
@EvanPlaice - Na gut, obwohl das immer noch die Blätter Akt des Druckens an den Client (die, auch nach einer serverseitigen Druckversion holen, würde dann entscheiden , was Gerät zu drucken und den Druckbefehl selbst senden, auch wenn die Befehl geht an einen Druckserver). Eine Anfrage nach einer druckerfreundlichen Version einer Ressource wäre dann logischerweise ... na ja ... GET.
Shauna
@Shauna Das Auslösen eines Druckauftrags nur über eine HTTP-Anforderung ist aufgrund der Browsersicherheit nicht möglich. Eine Anfrage für eine druckfreundliche Version ist nur eine GET-Anfrage. Sie müssen jedoch noch eine Möglichkeit angeben, dass der Browser die druckbare Version rendern soll. Sie könnten eine andere URL angeben, dies würde jedoch gegen die Prinzipien von REST verstoßen, da Sie tatsächlich keine andere Ressource anfordern, sondern nur eine andere Transformation derselben Ressource. Daher der Grund für die Angabe der Transformation über einen Abfrageparameter und / oder Inhaltstyp.
Evan Plaice
Ich habe nicht genug rep als Antwort zu schreiben, aber ich finde es interessant , dass tyk.io/rest-never-crud argumentiert , dass POST /customers/123/printeine gültige Sache zu tun.
6.

Antworten:

9

POSTbedeutet nicht "erstellen", sondern "verarbeiten". Sie können eine neue Ressource erstellen, indem Sie eine geeignete Anfrage an eine vorhandene Ressource senden (dh an senden /customers, um einen neuen Kunden zu erstellen). Sie können aber auch POSTalle anderen Aktionen ausfüllen, die keinem ordentlichen CRUD-Paradigma entsprechen.

Beim Drucken sollten Sie den Vorgang des Druckens als Ressource selbst betrachten. Sie bitten das System, einen "Druckauftrag" für Sie zu erstellen. Dies bedeutet, dass Sie eine prints/Ressource haben können, die als Container für alle angeforderten Ausdrucke fungiert. Wenn Sie etwas drucken möchten, senden Sie POSTein Dokument an diese Ressource, das alle Informationen zu dem Ausdruck enthält, den Sie erstellen möchten, und die zu druckenden Ressourcen mit Links dazu identifiziert.

Als JSON-Dokument könnte es folgendermaßen aussehen:

{
   contents: ["http://site/customers/12345"],
   paper-size: "A4",
   duplex: "true"
}

Natürlich müssen Sie dies so anpassen, dass es für das, was Sie tun möchten, relevant ist. Der Schlüssel ist, dass Sie andere zu druckende Ressourcen durch Angabe ihrer URL identifizieren.

Als Antwort auf die Anfrage können Sie einfach ein 200 OKoder ein zurückgeben 204 No-Contentund es als einen Vorgang zum Löschen und Vergessen behandeln. Wenn Sie es jedoch erweitern möchten, können Sie 201 Createddie URL des neu erstellten Druckauftrags zurückgeben und angeben, z /prints/12345.

Ein Benutzer kann dann GETin der Ressource eine Aktion ausführen , um den Status seines Druckauftrags (ausstehend, in Bearbeitung usw.) anzuzeigen, oder den Auftrag durch Ausgabe von abbrechen DELETE.

Sobald Sie das Problem in Bezug auf die Ressource umformuliert haben, sollte das RESTful-Design selbstverständlich sein und Ihnen die Möglichkeit geben, es auf eine Weise zu erweitern und zu verbessern, die Sie möglicherweise nicht sofort in Betracht gezogen haben.

Paul Turner
quelle
2
POST bedeutet normalerweise Erstellen / Einfügen, wohingegen Put normalerweise Aktualisieren, Speichern / Aktualisieren bedeutet. So ist es in REST definiert, auch wenn es nicht so ist, wie es normalerweise in HTML verwendet wird.
Evan Plaice
2
@EvanPlaize die HTTP-Spezifikationsnamen PUT als das Erstellungs- / Aktualisierungsverb (es verwendet ein Erstellungs- + Aktualisierungsmodell anstelle des bekannteren Erstellungs- + Abruf- + Aktualisierungsverbs) und POST ist das "Datenverarbeitungs" -Verb sowie das "Anfügungs" -Verb . Roy Fielding hat in seinem Blog POST als das Verb beschrieben, das verwendet wird, wenn Sie den Vorgang nicht standardisieren möchten. POST übernimmt die Semantik "Erstellen", wenn Sie in Betracht ziehen, ein neues Element an eine Sammlung von Elementen anzuhängen. In diesem Fall hat Tragedian mit POST den Nagel auf den Kopf getroffen, um einen Druckauftrag zu verarbeiten oder hinzuzufügen.
Rob
@RobY OK, das macht Sinn. Als Beispiel könnte PUT verwendet werden, um einen SPROC darzustellen, der zur Eingabe von Daten in eine Datenbank vorgesehen ist. Ein POST könnte die Zwischenschritte und Mutationen umfassen, die zum Sammeln / Vorbereiten dieser Daten erforderlich sind. Das Design der POST-Operation könnte sich ändern oder ersetzt werden, wenn sich das Design weiterentwickelt, aber die PUT-Operationen stellen das Modell dar, das (idealerweise) nicht geändert werden sollte. Ich würde meine Antwort aktualisieren, aber diese macht bereits einen großartigen Job, um den Unterschied zu erklären.
Evan Plaice
4

Ich habe das schon mal gemacht. Um ein Dokument zu drucken, gebe ich einfach eine PDF-Version einer Ressource zurück. Der Client muss nur eine GET-Anforderung für die Ressource mit Accept header application / pdf senden.

So vermeiden Sie auch das Erstellen eines neuen URI für temporäre Ressourcen wie Druckaufträge. Die Verwendung des HTTP-Headers ist ebenfalls Teil von REST und hält den URI sauber.

imel96
quelle
3

Fügen Sie einfach einen Parameter zum GET des aktuellen URI hinzu

Es ist ziemlich typisch, einen URI für mehrere Aktionen zu verwenden.

Wenn Sie von derselben Ressource, aber einer anderen Aktion sprechen, definieren Sie sie als Parameter.

/ customer / {id}? print = true

Wenn Sie dann Ihre GET-Methode definieren, erkennen Sie das Vorhandensein des Druckparameters und behandeln ihn anders.

REST wird folgendermaßen definiert:

  • POST - Erstellen Sie einen Datensatz, ein Asset oder eine Ressource
  • PUT - Update, Datensatz, Asset oder Ressource
  • LÖSCHEN - Entfernen eines Datensatzes, Assets oder einer Ressource

GET hingegen soll auf verschiedene Arten verwendet werden, da es in der Regel viele verschiedene Formen gibt, in denen eine Ressource abgerufen werden kann. Das ist auch der Grund, warum GET-Anforderungen als Abfragezeichenfolge dargestellt werden. Wenn Sie mit einer Datenbankressource gearbeitet haben, würden Sie eine Ansicht buchstäblich über eine Abfrage abrufen, REST wird jedoch absichtlich auf eine höhere Ebene abstrahiert, da es für die Verwendung mit vielen verschiedenen Ressourcentypen entwickelt wurde.

Die REST-Spezifikation ist ziemlich zukunftsweisend, obwohl APIs sie erst seit kurzem in großem Umfang verwenden.

Wenn Sie mehr über REST-Protokolle erfahren möchten, empfehlen wir Ihnen dringend, " Hasser, die HATEOAS hassen " zu lesen .


Aktualisieren:

@ Shauna wies auf eine interessante Lücke in meiner Argumentation hin. Es gibt keinen wahren richtigen Weg und viele Formen sind akzeptabel angesehen. Da Sie die Daten in eine andere Darstellung umwandeln möchten, ist es sinnvoll, die Transformation als neuen MIME-Typ zu definieren.

Beispielsweise könnten Sie den URI wie folgt darstellen:

/customer/{id}+print

Hier können Sie den Inhaltstyp der Antwort auf text / html + print setzen. Auf diese Weise haben Sie auch die Möglichkeit, in Zukunft weitere Transformationen zu definieren.

Beispielsweise:

// for application/json
/customer/{id}+json

// for application/atom+xml
/customer/{id}+atom

In jedem Fall sind alle Formen zulässig. Die Implementierung, für die Sie sich entscheiden, hängt mehr von Ihren persönlichen Vorlieben und den Fähigkeiten Ihres Servers ab.

Nebenbei: Lassen Sie mich das klarstellen, da es Verwirrung zu geben scheint. Der 'print'-Abfrageparameter und / oder der Inhaltstyp wird verwendet, um anzugeben, wie die Ressource transformiert wird. Nicht, wie ein physischer Druckauftrag ausgelöst wird. Aus Sicherheitsgründen wird der Zugriff auf Hardwareebene immer dem Benutzer / Client / Browser überlassen.

Evan Scholle
quelle
Hinzufügen - Alternativ zur Verwendung der Abfragezeichenfolge ( ?print=true) können Sie auch URI-Parameter (dh - /customer/{id}/printable) verwenden. Welche Sie verwenden, hängt weitgehend von dem Standard ab, für den Ihr System (CMS, Framework, Code im Allgemeinen) eingerichtet ist. Beide gelten als gültig und akzeptabel .
Shauna
@Shauna Technisch gesehen wäre der beste Ansatz, einen MIME-spezifischen Typ für das Drucken mit dem URI '/ customer / {id} + print' und einem Antwort-MIME-Typ für Text / html + print zu verwenden. Der Vorteil eines solchen Ansatzes besteht darin, dass Sie Transformationen für viele MIME-Typen (z. B. text / html, text / x-markdown, application / json usw.) für denselben URI erstellen können. Der Nachteil der von Ihnen vorgestellten Lösung ist, dass Sie für jeden MIME-Typ einen zusätzlichen URI erstellen (und eine andere Route definieren) müssen. Es vereitelt irgendwie den Zweck der Verwendung von REST.
Evan Plaice
(Fortsetzung) Ich würde argumentieren, dass URI-Hacks ein Anti-Pattern sind, das hauptsächlich von der ROR-Community eingeführt wurde, aber das bedeutet nicht, dass sie nicht nützlich sind. Mit der Einführung besserer HTTPd-Server auf niedriger Ebene wird es immer einfacher, REST so zu implementieren, dass das Potenzial voll ausgeschöpft wird. Seit den Tagen, in denen Apache und das Routing aller Daten über index.html die einzige Option waren, ist ein langer Weg zurückgelegt worden.
Evan Plaice
2
GET sollte keine Zustandsänderungen vornehmen oder Nebenwirkungen haben. Bedenken Sie, dass GET idempotent ist, was bedeutet, dass Middleware die Anforderung möglicherweise wiederholt, wenn sie nicht durchlaufen wurde. In diesem Fall wird bei jedem erneuten Versuch eine neue, frisch gedruckte Kopie des Dokuments erstellt. ;)
Rob
@RobY Ich ging davon aus, dass die Aktion "Drucken" den Vorgang des physischen Druckens des Dokuments nicht bewältigen würde, da dies vom Browser und vom Druckertreiber besser unterstützt würde. Die Medien- / Druckausgabe würde vielmehr eine "druckfreundliche" Darstellung des Dokuments zurückgeben. Daher bleibt die Idempotenz erhalten. Ein guter Grund, Druckaufträge zustandslos über das Internet zu versenden, wäre eine schlechte Zeit.
Evan Plaice