RESTful API: HTTP-Verben mit gemeinsamen oder bestimmten URLs?

25

Soll ich beim Erstellen einer RESTful-API HTTP-Verben unter derselben URL verwenden (sofern dies möglich ist) oder eine bestimmte URL pro Aktion erstellen?

Beispielsweise:

GET     /items      # Read all items
GET     /items/:id  # Read one item
POST    /items      # Create a new item
PUT     /items/:id  # Update one item
DELETE  /items/:id  # Delete one item

Oder mit bestimmten URLs wie:

GET     /items            # Read all items
GET     /item/:id         # Read one item
POST    /items/new        # Create a new item
PUT     /item/edit/:id    # Update one item
DELETE  /item/delete/:id  # Delete one item
53777A
quelle

Antworten:

46

In Ihrem letzteren Schema behalten Sie Verben in den URLs Ihrer Ressourcen. Dies sollte vermieden werden, da zu diesem Zweck die HTTP-Verben verwendet werden sollten. Umfassen Sie das zugrunde liegende Protokoll, anstatt es zu ignorieren, zu duplizieren oder zu überschreiben.

Schauen DELETE /item/delete/:idSie sich nur an , Sie platzieren die gleichen Informationen zweimal in der gleichen Anfrage. Dies ist überflüssig und sollte vermieden werden. Persönlich würde ich damit verwechselt werden. Unterstützt die API tatsächlich DELETEAnfragen? Was ist, wenn ich deletedie URL einfüge und stattdessen ein anderes HTTP-Verb verwende? Wird es zu irgendetwas passen? Wenn ja, welches wird ausgewählt? Als Kunde einer richtig gestalteten API sollte ich solche Fragen nicht stellen müssen.

Vielleicht brauchen Sie es, um Clients zu unterstützen, die keine Probleme DELETEoder PUTAnfragen haben. In diesem Fall würde ich diese Informationen in einem HTTP-Header übergeben. Einige APIs verwenden einen X-HTTP-Method-OverrideHeader für diesen speziellen Zweck (was meiner Meinung nach sowieso ziemlich hässlich ist). Ich würde die Verben aber auf keinen Fall in die Pfade setzen.

Gehen Sie für

GET     /items      # Read all items
GET     /items/:id  # Read one item
POST    /items      # Create a new item
PUT     /items/:id  # Update one item
DELETE  /items/:id  # Delete one item

Was an den Verben wichtig ist, ist, dass sie in der HTTP-Spezifikation bereits gut definiert sind. Wenn Sie diese Regeln einhalten, können Sie Caches, Proxys und möglicherweise andere Tools außerhalb Ihrer Anwendung verwenden, die die Semantik von HTTP verstehen, jedoch nicht die Semantik Ihrer Anwendung . Beachten Sie, dass der Grund, warum Sie vermeiden sollten, dass sie in Ihren URLs enthalten sind, nicht in RESTful-APIs besteht, die lesbare URLs erfordern. Es geht darum, unnötige Mehrdeutigkeiten zu vermeiden.

Darüber hinaus kann eine RESTful-API diese Verben (oder eine beliebige Teilmenge davon) einer beliebigen Anwendungssemantik zuordnen, sofern dies nicht gegen die HTTP-Spezifikation verstößt. Zum Beispiel ist es durchaus möglich , ein RESTful API , dass nur Anwendungen Anfragen zu bauen, wenn alle Operationen , die es ermöglicht , sind sowohl sicher und idempotent . Die obige Zuordnung ist nur ein Beispiel, das zu Ihrem Anwendungsfall passt und der Spezifikation entspricht. Es muss nicht unbedingt so sein.

Beachten Sie auch, dass für eine wirklich REST- konforme API niemals ein Programmierer umfangreiche Dokumentationen verfügbarer URLs lesen muss, solange Sie das Prinzip HATEOAS (Hypertext als Engine of Application State) einhalten, das eine der Kernannahmen von REST ist . Die Links können für den Menschen völlig unverständlich sein, solange die Client-Anwendung sie verstehen und verwenden kann, um mögliche Übergänge des Anwendungsstatus herauszufinden.

toniedzwiedz
quelle
4
In Abwesenheit von PUTund DELETEwürde ich es vorziehen, es dem Pfad hinzuzufügen, ohne es mit einer Abfragezeichenfolge zu unterscheiden. Es handelt sich nicht um eine Änderung der Abfragezeichenfolge an einer vorhandenen Operation. Es ist eine separate Operation.
Robert Harvey
4
@RobertHarvey in diesem Fall würde ich es trotzdem als Hack bezeichnen. Wie Sie sagen, es ist eine Operation und das würde ich nicht in den Weg legen, wenn ich eine API entwerfe, die darauf abzielt, RESTful zu sein. Das Platzieren in der Abfragezeichenfolge scheint weniger invasiv zu sein. Zwischenspeichern wird zwar verhindert, aber ich denke nicht, dass Antworten auf diese Art von Anforderungen trotzdem zwischengespeichert werden sollten. Außerdem kann der Benutzer der API auf einfache Weise die Methode angeben, ohne die URL analysieren oder erstellen zu müssen. Idealerweise sollte eine wirklich REST-konforme API die Hyperlinks bereitstellen, ohne dass die Clients selbst URLs erstellen müssen.
Toniedzwiedz
Wenn Sie nicht alle Verben haben, ist es sowieso nicht völlig RESTful, oder?
Robert Harvey
@RobertHarvey stimmt, aber ich behandle diese als Fallback, nicht als beabsichtigtes Design. Ich stelle mir vor, dass die API tatsächliche HTTP-Methoden unterstützen sollte. Wenn einige Clients sie aus irgendeinem Grund nicht implementieren können, können sie ihre Verwendung einfach durch diese Abfrageparameter ersetzen. Ein Proxy könnte diese sogar im Handumdrehen abrufen und die Anforderungen unter Verwendung echter HTTP-Verben in solche umwandeln, sodass sich der Server nicht einmal darum kümmern muss. Nur wenige APIs sind wirklich restvoll. Wenn es um generische Web-APIs geht, ist das wirklich Geschmackssache. Ich persönlich würde auf saubere URLs setzen. Einfacher zu verstehen, IMHO.
Toniedzwiedz
1
@RobertHarvey wie erklärt, es ist kaum die beabsichtigte Art, sie zu benutzen. Ich finde dies nur das kleinere von zwei Übeln, wenn Sie Kundenbeschränkungen überwinden müssen. Ich erinnere mich, dass ich eine Dokumentation für eine solche API gelesen habe, aber ich muss einige Ausgrabungen in meinem Browserverlauf / meinen Lesezeichen durchführen, um sie zu finden. Nun, da ich darüber nachdenke, könnte ein Header in diesem Fall besser sein. Würdest du zustimmen?
Toniedzwiedz
14

Der erste.

Eine URI / URL ist eine Ressourcen-ID (Hinweis im Namen: Uniform Resource Identifier). Mit der ersten Konvention ist die Ressource, über die gesprochen wird, wenn Sie "GET / user / 123" ausführen, und die Ressource, über die gesprochen wird, wenn Sie "DELETE / user / 123" ausführen, eindeutig dieselbe Ressource, da sie dieselbe URL haben.

Mit der zweiten Konvention können Sie nicht sicher sein, dass "GET / user / 123" und "DELETE / user / delete / 123" tatsächlich dieselbe Ressource sind, und es scheint, dass Sie eine verwandte Ressource anstelle der Ressource löschen Es wäre also ziemlich überraschend, wenn das Löschen /user/delete/123tatsächlich gelöscht wird /user/123. Wenn alle Vorgänge mit unterschiedlichen URLs arbeiten, fungiert der URI nicht mehr als Ressourcenkennung.

Wenn Sie sagen DELETE /user/123, sagen Sie "Benutzerdatensatz mit der ID 123 löschen". Wenn Sie sagen DELETE /user/delete/123, implizieren Sie anscheinend, dass Sie einen Benutzer-Löschdatensatz mit der ID 123 löschen. Dies ist wahrscheinlich nicht das, was Sie sagen möchten. Und selbst wenn Sie in dieser Situation das korrektere Verb verwenden: "POST / user / delete / 123", das besagt "Führe die Operation aus, die an 'user deletor with id 123' angehängt ist", ist es immer noch ein Umweg, einen Datensatz zu löschen (Dies ist vergleichbar mit der Substantivierung eines Verbs in Englisch).

Eine Möglichkeit, über URL nachzudenken, besteht darin, sie wie Zeiger auf Objekte und Ressourcen als Objekte in der objektorientierten Programmierung zu behandeln. Wenn Sie das tun GET /user/123, DELETE /user/123können Sie denken , denken Sie an sie als Methoden im Objekt: [/user/123].get(), [/user/123].delete()wo der []wie ein Zeiger ist Dereferenzierungsoperator aber für URLs (wenn Sie eine Sprache kennen , die Zeiger haben). Eines der Grundprinzipien von REST ist die einheitliche Schnittstelle, dh ein kleiner und begrenzter Satz von Verben / Methoden, die für alles in einem riesigen Netzwerk von Ressourcen / Objekten funktionieren.

Daher ist der erste besser.

PS: Natürlich geht es hier um REST auf die reinste Art und Weise. Manchmal ist Praktikabilität besser als Reinheit, und Sie müssen Zugeständnisse für gehirntote Kunden oder ein Framework machen, das es schwierig macht, eine ordnungsgemäße REST durchzuführen.

Lüge Ryan
quelle
+1 für das OOP-Beispiel :)
53777A
6

(Entschuldigung, mein erstes Mal habe ich das / edit / und / delete / in (2) verpasst ...)

Die Idee des URI ist, dass es sich nicht um einen Methodenaufruf , sondern um einen Bezeichner einer adressierbaren Ressource handelt . Der URI sollte also auf eine bestimmte Ressource verweisen. Und wenn Sie den URI verteidigen, sollten Sie immer die gleiche Ressource erhalten.

Das heißt, Sie sollten URIs genauso betrachten wie den Primärschlüssel einer Zeile in einer Datenbank. Es identifiziert eindeutig etwas: Universal Resource Identifier.

Unabhängig davon, ob Sie den Plural oder den Singular verwenden, sollte der URI eher ein Bezeichner als ein Aufruf sein . Was Sie versuchen zu tun , geht in dem Verfahren, nämlich: GET (get), PUT (create / update), DELETE (löschen) oder POST (alles andere).

"/ Item / delete / 123" unterbricht also REST, weil es nicht auf eine Ressource verweist, sondern eher ein Methodenaufruf ist.

(Nur semantisch gesehen sollten Sie in der Lage sein, einen URI abzurufen, zu entscheiden, dass er veraltet ist, und dann denselben URI zu LÖSCHEN, da es sich um einen Bezeichner handelt. Wenn der GET-URI nicht über "/ delete /" verfügt und DELETE dies tut, dann widerspricht das der HTTP-Semantik. Sie senden 2 oder mehr URIs pro Ressource, wobei 1 ausreicht.)

Nun, der Cheat ist der folgende: Es gibt keine wirklich klare Definition dessen, was eine Ressource ist und was nicht. Daher besteht die übliche Dodge in REST darin, ein "Verarbeitungsnomen" zu definieren und den URI darauf zu verweisen. Das ist so ziemlich ein Wortspiel, aber es befriedigt die Semantik.

Wenn Sie dies beispielsweise aus irgendeinem Grund wirklich nicht verwenden können:

DELETE /items/123

Sie könnten der Welt mitteilen, dass Sie eine "Löscher" -Verarbeitungsressource haben und verwenden

POST /items/deletor  { id: 123 }

Das sieht RPC (Remote Procedure Call) sehr ähnlich, aber es fällt durch die große Lücke der "data processing" -Klausel der POST-Spezifikation, die in der HTTP-Spezifikation genannt wird.

Aber das zu tun ist eine Art außergewöhnlich, und wenn Sie können die gemeinsame PUT für erstellen / aktualisieren verwenden, DELETE zum Löschen und POST für Anfügen, erstellen und alles andere, dann Sie sollten , denn es ist eine Standard - Nutzung von HTTP. Wenn Sie jedoch einen kniffligen Fall wie "Festschreiben" oder "Veröffentlichen" oder "Redigieren" haben, erfüllt der Fall für die Verwendung eines Prozessornomens die REST-Puristen und bietet Ihnen dennoch die Semantik, die Sie benötigen.

rauben
quelle