Ich schreibe einen RESTful-Service für ein Kundenverwaltungssystem und versuche, die beste Vorgehensweise zum teilweisen Aktualisieren von Datensätzen zu finden. Ich möchte beispielsweise, dass der Anrufer den vollständigen Datensatz mit einer GET-Anforderung lesen kann. Zum Aktualisieren sind jedoch nur bestimmte Vorgänge im Datensatz zulässig, z. B. das Ändern des Status von AKTIVIERT in DEAKTIVIERT. (Ich habe komplexere Szenarien als diese)
Ich möchte aus Sicherheitsgründen nicht, dass der Anrufer den gesamten Datensatz nur mit dem aktualisierten Feld übermittelt (es fühlt sich auch wie ein Overkill an).
Gibt es eine empfohlene Methode zum Erstellen der URIs? Beim Lesen der REST-Bücher scheinen RPC-Aufrufe verpönt zu sein.
Wenn der folgende Aufruf den vollständigen Kundendatensatz für den Kunden mit der ID 123 zurückgibt
GET /customer/123
<customer>
{lots of attributes}
<status>ENABLED</status>
{even more attributes}
</customer>
Wie soll ich den Status aktualisieren?
POST /customer/123/status
<status>DISABLED</status>
POST /customer/123/changeStatus
DISABLED
...
Update : Um die Frage zu erweitern. Wie integriert man "Business Logic Calls" in eine REST-API? Gibt es einen vereinbarten Weg, dies zu tun? Nicht alle Methoden sind von Natur aus CRUD. Einige sind komplexer, wie " sendEmailToCustomer (123) ", " mergeCustomers (123, 456) ", " countCustomers () ".
POST /customer/123?cmd=sendEmail
POST /cmd/sendEmail?customerId=123
GET /customer/count
POST
von Roy Fielding selbst: roy.gbiv.com/untangled/2009/it-is-okay-to-use-post, in dem die Grundidee lautet: Wenn nicht Es handelt sich nicht um eine Methode (wieGET
oderPUT
), die sich ideal für Ihren Einsatz eignetPOST
.Antworten:
Sie haben grundsätzlich zwei Möglichkeiten:
Verwenden Sie
PATCH
(beachten Sie jedoch, dass Sie Ihren eigenen Medientyp definieren müssen, der genau angibt, was passieren wird).Verwenden Sie
POST
diese Option für eine Unterressource und geben Sie sie zurück. 303 Siehe Andere, wobei der Standortkopf auf die Hauptressource verweist. Mit dem 303 soll dem Client mitgeteilt werden: "Ich habe Ihren POST durchgeführt, und der Effekt war, dass eine andere Ressource aktualisiert wurde. Siehe Standortkopfzeile für welche Ressource dies war." POST / 303 ist für iterative Ergänzungen zu Ressourcen vorgesehen, um den Status einer Hauptressource aufzubauen, und eignet sich perfekt für Teilaktualisierungen.quelle
Sie sollten POST für Teilaktualisierungen verwenden.
Um Felder für Kunde 123 zu aktualisieren, senden Sie einen POST an / customer / 123.
Wenn Sie nur den Status aktualisieren möchten, können Sie auch auf / customer / 123 / status setzen.
Im Allgemeinen sollten GET-Anforderungen keine Nebenwirkungen haben, und PUT dient zum Schreiben / Ersetzen der gesamten Ressource.
Dies folgt direkt aus HTTP, wie hier zu sehen: http://en.wikipedia.org/wiki/HTTP_PUT#Request_methods
quelle
/customer/123
das Offensichtliche schaffen sollte, das logischerweise unter Kunde 123 liegt. Vielleicht eine Bestellung? PUT to/customer/123/status
scheint sinnvoller zu sein, vorausgesetzt, der POST/customers
erstellt implizit einstatus
(und nimmt an, dass dies ein legitimer REST ist).POST
-requests nicht brauchen nicht idempotent zu sein. Und wie gesagt,PUT
muss eine ganze Ressource ersetzen.Sie sollten PATCH für Teilaktualisierungen verwenden - entweder mithilfe von Json-Patch-Dokumenten (siehe http://tools.ietf.org/html/draft-ietf-appsawg-json-patch-08 oder http://www.mnot.net/). blog / 2012/09/05 / patch ) oder das XML-Patch-Framework (siehe http://tools.ietf.org/html/rfc5261 ). Meiner Meinung nach passt json-patch am besten zu Ihrer Art von Geschäftsdaten.
PATCH mit JSON / XML-Patchdokumenten bietet eine sehr direkte Semantik für Teilaktualisierungen. Wenn Sie POST mit geänderten Kopien des Originaldokuments für Teilaktualisierungen verwenden, treten bald Probleme auf, bei denen fehlende Werte (oder vielmehr Nullwerte) entweder "Diese Eigenschaft ignorieren" oder "Diese Eigenschaft auf" setzen sollen leerer Wert "- und das führt zu einem Hasenloch gehackter Lösungen, die am Ende zu Ihrem eigenen Patch-Format führen.
Eine ausführlichere Antwort finden Sie hier: http://soabits.blogspot.dk/2013/01/http-put-patch-or-post-partial-updates.html .
quelle
Ich habe ein ähnliches Problem. PUT für eine Unterressource scheint zu funktionieren, wenn Sie nur ein einzelnes Feld aktualisieren möchten. Manchmal möchten Sie jedoch eine Reihe von Dingen aktualisieren: Stellen Sie sich ein Webformular vor, das die Ressource mit der Option zum Ändern einiger Einträge darstellt. Die Übermittlung des Formulars durch den Benutzer sollte nicht zu mehreren PUTs führen.
Hier sind zwei Lösungen, die mir einfallen:
Führen Sie einen PUT mit der gesamten Ressource durch. Definieren Sie auf der Serverseite die Semantik, nach der ein PUT mit der gesamten Ressource alle Werte ignoriert, die sich nicht geändert haben.
Führen Sie einen PUT mit einer Teilressource durch. Definieren Sie auf der Serverseite die Semantik als Zusammenführung.
2 ist nur eine Bandbreitenoptimierung von 1. Manchmal ist 1 die einzige Option, wenn die Ressource definiert, dass einige Felder Pflichtfelder sind (denken Sie an Protopuffer).
Das Problem bei beiden Ansätzen ist, wie ein Feld gelöscht wird. Sie müssen einen speziellen Nullwert definieren (insbesondere für Protopuffer, da für Protopuffer keine Nullwerte definiert sind), der zum Löschen des Felds führt.
Bemerkungen?
quelle
Zum Ändern des Status besteht meines Erachtens ein RESTful-Ansatz darin, eine logische Unterressource zu verwenden, die den Status der Ressourcen beschreibt. Diese IMO ist sehr nützlich und sauber, wenn Sie weniger Status haben. Dadurch wird Ihre API aussagekräftiger, ohne dass die vorhandenen Vorgänge für Ihre Kundenressource erzwungen werden müssen.
Beispiel:
Der POST-Service sollte den neu erstellten Kunden mit der folgenden ID zurückgeben:
Das GET für die erstellte Ressource würde den Ressourcenspeicherort verwenden:
Ein GET / customer / 123 / inactive sollte 404 zurückgeben
Bei der PUT-Operation wird ohne Angabe einer Json-Entität lediglich der Status aktualisiert
Durch die Bereitstellung einer Entität können Sie den Inhalt des Kunden aktualisieren und gleichzeitig den Status aktualisieren.
Sie erstellen eine konzeptionelle Unterressource für Ihre Kundenressource. Dies steht auch im Einklang mit Roy Fieldings Definition einer Ressource: "... Eine Ressource ist eine konzeptionelle Zuordnung zu einer Reihe von Entitäten, nicht die Entität, die der Zuordnung zu einem bestimmten Zeitpunkt entspricht ..." In diesem Fall ist die Die konzeptionelle Zuordnung erfolgt von Kunde zu Kunde mit dem Status = AKTIV.
Lesevorgang:
Wenn Sie diese Anrufe direkt nach dem anderen tätigen, muss einer von ihnen den Status 404 zurückgeben, enthält die erfolgreiche Ausgabe möglicherweise nicht den impliziten Status. Natürlich können Sie weiterhin GET / customer / 123? Status = ACTIVE | INACTIVE verwenden, um die Kundenressource direkt abzufragen.
Die DELETE-Operation ist interessant, da die Semantik verwirrend sein kann. Sie haben jedoch die Möglichkeit, diesen Vorgang für diese konzeptionelle Ressource nicht zu veröffentlichen oder gemäß Ihrer Geschäftslogik zu verwenden.
Dieser kann Ihren Kunden in den Status DELETED / DISABLED oder in den entgegengesetzten Status (ACTIVE / INACTIVE) versetzen.
quelle
Dinge, die Sie Ihrer erweiterten Frage hinzufügen sollten. Ich denke, Sie können oft kompliziertere Geschäftsaktionen perfekt gestalten. Aber Sie müssen den Methoden- / Verfahrensstil des Denkens verraten und mehr in Ressourcen und Verben denken.
Mailversand
Die Implementierung dieser Ressource + POST würde dann die Mail senden. Bei Bedarf können Sie dann etwas wie / customer / 123 / outbox anbieten und dann Ressourcenlinks zu / customer / mails / {mailId} anbieten.
Kundenanzahl
Sie können damit wie mit einer Suchressource umgehen (einschließlich Suchmetadaten mit Paging und num-found-Informationen, mit denen Sie die Anzahl der Kunden angeben können).
quelle
Verwenden Sie PUT zum Aktualisieren unvollständiger / teilweiser Ressourcen.
Sie können jObject als Parameter akzeptieren und seinen Wert analysieren, um die Ressource zu aktualisieren.
Nachfolgend finden Sie die Funktion, die Sie als Referenz verwenden können:
quelle
In Bezug auf Ihr Update.
Ich glaube, das Konzept von CRUD hat einige Verwirrung hinsichtlich des API-Designs verursacht. CRUD ist ein allgemeines Low-Level-Konzept für grundlegende Operationen, die mit Daten ausgeführt werden sollen, und HTTP-Verben sind lediglich Anforderungsmethoden ( vor 21 Jahren erstellt ), die einer CRUD-Operation zugeordnet werden können oder nicht. Versuchen Sie tatsächlich, das Vorhandensein des Akronyms CRUD in der HTTP 1.0 / 1.1-Spezifikation zu finden.
Eine sehr gut erläuterte Anleitung, die eine pragmatische Konvention anwendet, finden Sie in der API-Dokumentation zur Google Cloud-Plattform . Es beschreibt die Konzepte hinter der Erstellung einer ressourcenbasierten API, die eine große Menge an Ressourcen gegenüber Vorgängen hervorhebt, und enthält die von Ihnen beschriebenen Anwendungsfälle. Obwohl es sich nur um ein Kongressdesign für ihr Produkt handelt, halte ich es für sehr sinnvoll.
Das Grundkonzept hier (und eines, das viel Verwirrung stiftet) ist die Zuordnung zwischen "Methoden" und HTTP-Verben. Eine Sache ist zu definieren, welche "Operationen" (Methoden) Ihre API über welche Arten von Ressourcen ausführt (z. B. eine Kundenliste abrufen oder eine E-Mail senden), und eine andere sind die HTTP-Verben. Es muss eine Definition sowohl der Methoden als auch der Verben geben, die Sie verwenden möchten, und eine Zuordnung zwischen ihnen .
Er sagt auch , dass, wenn eine Operation nicht genau mit einem Standardverfahren abbildet (
List
,Get
,Create
,Update
,Delete
in diesem Fall), kann eine „Custom - Methoden“, wie verwendenBatchGet
, die mehrere Objekte - ID Eingabe mehrere Objekte abruft , basierend auf oderSendEmail
.quelle
RFC 7396 : JSON Merge Patch (veröffentlicht vier Jahre nach Veröffentlichung der Frage) beschreibt die Best Practices für einen PATCH in Bezug auf Format und Verarbeitungsregeln.
Kurz gesagt, Sie senden einen HTTP-PATCH an eine Zielressource mit dem Medientyp application / merge-patch + json MIME und einem Body, der nur die Teile darstellt, die Sie ändern / hinzufügen / entfernen möchten, und befolgen dann die folgenden Verarbeitungsregeln.
Regeln :
Beispiel für Testfälle, die die obigen Regeln veranschaulichen (wie im Anhang dieses RFC zu sehen):
quelle
Überprüfen Sie http://www.odata.org/
Es definiert die MERGE-Methode, also wäre es in Ihrem Fall ungefähr so:
Nur die
status
Eigenschaft wird aktualisiert und die anderen Werte bleiben erhalten.quelle
MERGE
ein gültiges HTTP-Verb?MERGE was used to do PATCH before PATCH existed. Now that we have PATCH, we no longer need MERGE.
Siehe docs.oasis-open.org/odata/new-in-odata/v4.0/cn01/…Es spielt keine Rolle. In Bezug auf REST können Sie kein GET ausführen, da es nicht zwischengespeichert werden kann. Es spielt jedoch keine Rolle, ob Sie POST oder PATCH oder PUT oder was auch immer verwenden, und es spielt keine Rolle, wie die URL aussieht. Wenn Sie REST ausführen, ist es wichtig, dass diese Darstellung den Clientstatusübergangsoptionen bietet, wenn Sie eine Darstellung Ihrer Ressource vom Server erhalten.
Wenn Ihre GET-Antwort Statusübergänge hatte, muss der Client nur wissen, wie er sie liest, und der Server kann sie bei Bedarf ändern. Hier wird ein Update mit POST durchgeführt. Wenn es jedoch in PATCH geändert wurde oder wenn sich die URL ändert, weiß der Client immer noch, wie ein Update durchgeführt wird:
Sie können sogar die erforderlichen / optionalen Parameter auflisten, die der Client an Sie zurückgeben kann. Das hängt von der Anwendung ab.
Für den Geschäftsbetrieb ist dies möglicherweise eine andere Ressource als die Kundenressource. Wenn Sie eine E-Mail an den Kunden senden möchten, handelt es sich bei diesem Service möglicherweise um eine eigene Ressource, an die Sie POSTEN können. Daher können Sie den folgenden Vorgang in die Kundenressource aufnehmen:
Einige gute Videos und ein Beispiel für die REST-Architektur des Präsentators sind diese. Stormpath verwendet nur GET / POST / DELETE, was in Ordnung ist, da REST nichts damit zu tun hat, welche Operationen Sie verwenden oder wie URLs aussehen sollten (außer GETs sollten zwischenspeicherbar sein):
https://www.youtube.com/watch?v=pspy1H6A3FM ,
https://www.youtube.com/watch?v=5WXYw4J4QOU ,
http://docs.stormpath.com/rest/quickstart/
quelle