Beim Entwerfen einer RESTful-Schnittstelle wird die Semantik der Anforderungstypen als entscheidend für den Entwurf erachtet.
- GET - Listet das Element auf oder ruft es ab
- PUT - Sammlung oder Element ersetzen
- POST - Erstellt eine Sammlung oder ein Element
- LÖSCHEN - Nun, ähm, lösche Sammlung oder Element
Dies scheint jedoch nicht das Konzept der "Suche" abzudecken.
ZB beim Entwerfen einer Suite von Webdiensten, die eine Jobsucheseite unterstützen, müssen Sie möglicherweise folgende Anforderungen erfüllen:
- Erhalten Sie individuelle Stellenanzeigen
- GET to
domain/Job/{id}/
- GET to
- Stellenanzeige erstellen
- POST zu
domain/Job/
- POST zu
- Stellenanzeige aktualisieren
- PUT to
domain/Job/
- PUT to
- Stellenanzeige löschen
- LÖSCHEN bis
domain/Job/
- LÖSCHEN bis
"Get All Jobs" ist auch einfach:
- GET to
domain/Jobs/
Wie aber fällt die Jobsuche in diese Struktur?
Sie könnten behaupten, dass es sich um eine Variante der "Listensammlung" handelt, die implementiert wird als:
- GET to
domain/Jobs/
Suchen können jedoch komplex sein und es ist durchaus möglich, eine Suche zu erstellen, die eine lange GET-Zeichenfolge generiert. Das heißt, wenn hier auf eine SO-Frage verwiesen wird , treten Probleme bei der Verwendung von GET-Zeichenfolgen auf, die länger als etwa 2000 Zeichen sind.
Ein Beispiel könnte eine facettierte Suche sein - Fortsetzung des Beispiels "Job".
Ich kann die Suche nach Facetten - "Technologie", "Berufsbezeichnung", "Disziplin" sowie nach Freitext-Stichwörtern, Berufsalter, Standort und Gehalt - zulassen.
Mit einer fließenden Benutzeroberfläche und einer Vielzahl von Technologien und Berufsbezeichnungen ist es möglich, dass eine Suche eine Vielzahl von Facettenauswahlmöglichkeiten umfasst.
Wenn Sie dieses Beispiel an Lebensläufen anstatt an Jobs anpassen, erhalten Sie noch mehr Facetten, und Sie können sich sehr leicht eine Suche mit hundert ausgewählten Facetten oder sogar nur 40 Facetten mit jeweils 50 Zeichen vorstellen (z. B. Jobtitel, Universitätsnamen, Arbeitgebernamen).
In diesem Fall ist es möglicherweise wünschenswert, einen PUT oder POST zu verschieben, um sicherzustellen, dass die Suchdaten korrekt gesendet werden. Z.B:
- POST zu
domain/Jobs/
Aber semantisch ist das eine Anweisung, eine Sammlung zu erstellen.
Sie können dies auch als Erstellung einer Suche ausdrücken:
- POST zu
domain/Jobs/Search/
oder (wie von burninggramma unten vorgeschlagen)
- POST zu
domain/JobSearch/
Semantisch mag es sinnvoll erscheinen, aber Sie erstellen eigentlich nichts, Sie fordern Daten an.
Semantisch ist es also ein GET , aber es wird nicht garantiert , dass GET das unterstützt, was Sie brauchen.
Die Frage ist also: Versuchen Sie, das REST-konforme Design so gut wie möglich beizubehalten, und stellen Sie dabei sicher, dass ich mich an die Einschränkungen von HTTP halte. Welches Design eignet sich am besten für eine Suche?
quelle
domain/Jobs?keyword={keyword}
. Das funktioniert gut für mich :) Ich hoffe, dass dasSEARCH
Verb zum Standard wird. programmers.stackexchange.com/questions/233158/…Antworten:
Sie sollten nicht vergessen, dass GET- Anforderungen gegenüber anderen Lösungen einige überlegene Vorteile haben :
1) GET-Anfragen können von der URL-Leiste kopiert werden, sie werden von Suchmaschinen verdaut, sie sind "freundlich". Wobei "freundlich" bedeutet, dass eine GET-Anforderung normalerweise nichts in Ihrer Anwendung ändern sollte (idempotent) . Dies ist der Standardfall für eine Suche.
2) Alle diese Konzepte sind nicht nur für Benutzer und Suchmaschinen von großer Bedeutung , sondern auch vom architektonischen Standpunkt des API-Designs aus.
3) Wenn Sie eine Problemumgehung mit POST / PUT erstellen, haben Sie Probleme, an die Sie gerade nicht denken. Zum Beispiel im Falle eines Browsers die Navigationstaste Zurück / Seite aktualisieren / Verlauf. Diese können natürlich gelöst werden, aber das wird eine andere Problemumgehung sein, dann noch eine und noch eine ...
In Anbetracht dessen wäre mein Rat :
a) Sie sollten in der Lage sein, mithilfe einer cleveren Parameterstruktur in Ihr GET zu passen . Im Extremfall können Sie sich sogar für eine Taktik wie diese Google-Suche entscheiden, bei der ich viele Parameter festgelegt habe. Trotzdem handelt es sich um eine sehr kurze URL.
b) Erstellen Sie eine andere Entität in Ihrer Bewerbung wie JobSearch . Vorausgesetzt, Sie haben so viele Optionen, ist es wahrscheinlich, dass Sie diese Suchanfragen ebenfalls speichern und verwalten müssen, sodass Ihre Anwendung nur bereinigt wird. Sie können mit den JobSearch- Objekten als Ganzes arbeiten, was bedeutet, dass Sie sie einfacher testen / verwenden können .
Persönlich würde ich versuchen, mit all meinen Krallen zu kämpfen, um es mit a) fertig zu machen, und wenn alle Hoffnung verloren ist, würde ich mit Tränen in den Augen zu Option b) zurückkriechen .
quelle
domain/Jobs/Search/
, vielleicht mitdomain/JobsSearch/
stattdessen oder meintest du etwas anderes? Könntest Du das erläutern?TL; DR: GET zum Filtern, POST zum Suchen
Ich unterscheide zwischen dem Filtern der Ergebnisse aus der Auflistung einer Sammlung und einer komplexen Suche. Der Lackmustest, den ich benutze, ist im Grunde genommen eine komplexere Suche, die POST erfordert, wenn ich mehr als Filterung (Positiv, Negativ oder Bereich) benötige.
Dies wird tendenziell verstärkt, wenn man über die Rückgabe nachdenkt. Normalerweise verwende ich GET nur, wenn eine Ressource einen größtenteils vollständigen Lebenszyklus hat (PUT, DELETE, GET, Collection GET) . In der Regel wird in einer Auflistung GET eine Liste von URIs zurückgegeben, die die REST-Ressourcen sind, aus denen diese Auflistung besteht. Bei einer komplexen Abfrage greife ich möglicherweise auf mehrere Ressourcen zurück, um die Antwort zu erstellen (denken Sie an einen SQL-Join), sodass ich keine URIs, sondern tatsächliche Daten zurücksende. Das Problem ist, dass die Daten nicht in einer Ressource dargestellt werden, sodass ich immer Daten zurückgeben muss. Dies scheint mir ein eindeutiger Fall zu sein, bei dem ein POST erforderlich ist.
-
Es ist schon eine Weile her und mein ursprünglicher Post war ein bisschen schlampig, also dachte ich, ich würde aktualisieren.
GET ist die intuitive Wahl für die Rückgabe der meisten Arten von Daten, Sammlungen von REST-Ressourcen, strukturierten Daten einer Ressource und sogar einzelner Nutzdaten (Bilder, Dokumente usw.).
POST ist die Catchall-Methode für alles, was nicht unter GET, PUT, DELETE usw. zu passen scheint.
An dieser Stelle denke ich, dass einfache Suchen und Filtern über GET intuitiv sinnvoll sind. Komplexe Suchvorgänge sind persönlichen Vorlieben unterworfen, insbesondere wenn Sie Aggregationsfunktionen, Kreuzkorrelationen (Joins), Neuformatierungen usw. verwenden. Ich würde sagen, die GET-Parameter sollten nicht zu lang werden, und es handelt sich um eine umfangreiche Abfrage (unabhängig davon, wie sie strukturiert ist) ) kann als POST-Anfragetext oft sinnvoller sein.
Ich betrachte auch den Erfahrungsaspekt der API-Nutzung. Im Allgemeinen möchte ich die meisten Methoden so einfach und intuitiv wie möglich gestalten. Ich werde flexiblere (und daher komplexere) Aufrufe in POSTs und auf einem anderen Ressourcen-URI übertragen, insbesondere wenn dies nicht mit dem Verhalten anderer REST-Ressourcen in derselben API übereinstimmt.
In beiden Fällen ist die Konsistenz wahrscheinlich wichtiger als die Suche in GET oder POST.
Hoffe das hilft.
quelle
GET /class?queryParams
. Aus der Sicht eines Benutzers war die "Klasse" immer eine Sache und Sie mussten keine seltsamen SQL-Joins ausführen.In REST ist die Ressourcendefinition sehr breit. Es ist wirklich so, wie Sie einige Daten bündeln möchten.
Der Haupt-URI von Google verweist beispielsweise auf eine Sammlungsressource mit "Links zu jeder Website im Internet". Abfrageparameter beschränken diese auf die Websites, die Sie anzeigen möchten.
(URI = Universal Resource Identifier, davon URL = Universal Resource Locator, wobei das vertraute "http: //" das Standardformat für einen URI ist. URL ist also ein Locator, aber in REST ist es gut, dies auf einen Resource Identifier zu verallgemeinern Die Leute benutzen sie jedoch austauschbar.)
Verwenden Sie dann POST, das heißt das Append- oder Prozessverb, um dieser Sammlung neue Elemente hinzuzufügen:
Beachten Sie, dass es für das
job
Objekt jeweils die gleiche Struktur gibt . Ein Client kann mithilfe von Abfrageparametern eine Sammlung von Jobs abrufen, um die Suche einzugrenzen, und dann dasselbe Format für eines der Elemente verwenden, um einen neuen Job zu veröffentlichen. Oder es kann eines dieser Elemente nehmen und zu seinem URI PUT, um dieses zu aktualisieren.Bei sehr langen oder komplizierten Abfragezeichenfolgen ist es gemäß der Konvention in Ordnung, diese stattdessen als POST-Anforderungen zu senden. Bündeln Sie die Abfrageparameter als Name / Wert-Paare oder verschachtelte Objekte in einer JSON- oder XML-Struktur und senden Sie sie im Hauptteil der Anforderung. Beispiel: Ihre Abfrage enthält verschachtelte Daten anstelle einer Reihe von Name / Wert-Paaren. Die HTTP-Spezifikation für POST beschreibt sie als das Anhänge- oder Prozessverb. (Wenn Sie ein Schlachtschiff durch eine Lücke in REST segeln möchten, verwenden Sie POST.)
Ich würde das allerdings als Fallback-Plan verwenden.
Was Sie jedoch verlieren, wenn Sie dies tun, ist a) GET ist nullpotent - das heißt, es ändert nichts - POST ist nichts. Wenn der Aufruf fehlschlägt, wird Middleware die Ergebnisse nicht automatisch wiederholen oder zwischenspeichern. 2) Mit den Suchparametern im Hauptteil können Sie den URI nicht mehr ausschneiden und einfügen. Das heißt, der URI ist kein spezifischer Bezeichner für die gewünschte Suche.
Unterscheiden zwischen "erstellen" und "suchen". Es gibt einige Optionen, die mit der REST-Praxis vereinbar sind:
Sie können dies in der URI tun, indem Sie dem Namen der Sammlung etwas hinzufügen, z. B. Jobsuche anstelle von Jobs. Das bedeutet nur, dass Sie die Suchsammlung als separate Ressource behandeln.
Da es sich bei der Semantik von POST sowohl um einen Anhänge-ODER-Prozess handelt, können Sie Suchkörper mit der Nutzlast identifizieren. Wie {job: ...} vs. {search: ...}. Es liegt an der POST-Logik, sie entsprechend zu veröffentlichen oder zu verarbeiten.
Das ist so ziemlich eine Vorliebe für Design / Implementierung. Ich glaube nicht, dass es eine klare Konvention gibt.
Wie Sie bereits dargelegt haben, besteht die Idee darin, eine Sammlungsressource für zu definieren
jobs
Suche mit GET + Abfrageparametern, um die Suche einzugrenzen. Lange oder strukturierte Datenabfragen gehen in den Hauptteil eines POST (möglicherweise in eine separate Suchsammlung). Mit POST erstellen, um an die Sammlung anzuhängen. Und aktualisieren Sie mit PUT auf eine bestimmte URI.
(FWIW die Stilkonvention mit URIs besteht darin, alle Kleinbuchstaben mit durch Bindestriche getrennten Wörtern zu verwenden. Aber das bedeutet nicht, dass Sie es auf diese Weise tun müssen.)
(Außerdem sollte ich sagen, dass es aus Ihrer Frage klar hervorgeht, dass Sie einen langen Weg zurücklegen. Ich habe die Dinge ausdrücklich so formuliert, dass sie in einer Reihe stehen, aber Ihre Frage hat die meisten semantischen Fragen in dieser Frage bereits beantwortet Antwort: Ich habe es nur mit ein wenig Konvention und Übung geschnürt.)
quelle
route
die Auswahl der Verarbeitung nicht wirklich bewältigt werden kann. Das müsste ich mir ansehen ...Im Allgemeinen verwende ich OData-Abfragen, die als GET-Aufruf fungieren, aber es Ihnen ermöglichen, die zurückgegebenen Eigenschaften einzuschränken und sie zu filtern.
Sie verwenden Token wie
$select=
und$filter=
so erhalten Sie einen URI, der ungefähr so aussieht:Sie können auch mit
$skip
und$top
und bestellen.Weitere Informationen finden Sie unter OData.org . Sie haben nicht angegeben, welche Sprache Sie verwenden, aber wenn es sich um ASP.NET handelt, unterstützt die WebApi-Plattform OData-Abfragen. Für andere (PHP usw.) gibt es wahrscheinlich Bibliotheken, mit denen Sie sie in Datenbankabfragen übersetzen können.
quelle
JobsNearMeAddedInTheLast7Days
oder was auch immer erstellen , um die Abfrage zu kapseln, die für OData zu lang / komplex ist, und sie dann nur über GET-Aufrufe verfügbar zu machen .Ein zu berücksichtigender Ansatz besteht darin, die Menge möglicher Abfragen als Sammlungsressource zu behandeln, z
/jobs/filters
.POST
Anfragen an diese Ressource, mit den Abfrageparametern in dem Körper, werden entweder eine neue Ressource bestehende gleichwertige Filter und geben eine URL enthält , dessen ID erstellen oder identifizieren:/jobs/filters/12345
.Die ID kann dann in einer GET - Anforderung für Aufträge verwendet werden:
/jobs?filter=12345
. NachfolgendeGET
Anforderungen an die Filterressource geben die Definition des Filters zurück.Dieser Ansatz hat den Vorteil, dass Sie vom Abfrageparameterformat für die Filterdefinition befreit werden und möglicherweise mehr Leistung für die Definition komplexer Filter erhalten. OR-Bedingungen sind ein Beispiel, von dem ich mir vorstellen kann, dass sie mit Abfragezeichenfolgen nur schwer zu erreichen sind.
Ein Nachteil dieses Ansatzes besteht darin, dass Sie die Lesbarkeit der URL verlieren (obwohl dies durch Abrufen der Definition über eine
GET
Anforderung für die Filterressource verringert werden kann). Aus diesem Grund möchten Sie möglicherweise auch dieselbe oder eine Teilmenge der Abfrageparameter für die/jobs
Ressource unterstützen, die Sie für eine Filterressource unterstützen würden. Dies könnte für kürzere Abfragen verwendet werden. Wenn diese Funktion bereitgestellt wird,/jobs
sollte die Implementierung bei Verwendung von Abfrageparametern für die Ressource intern eine Filterressource erstellen / wiederverwenden und einen302
oder303
-Status zurückgeben, der die URL in Form von angibt , um die Cachefreundlichkeit zwischen den beiden Filtertypen zu gewährleisten/jobs?filter=12345
.quelle
GET /jobs/37
ein Ergebnis stellen und ein Ergebnis erhalten, dann löscht jemand die Ressource und 2 Sekunden später gibt dieselbe Anfrage eine 404 zurück. Ebenso, wenn SiePOST /searches
und Sie zu einem Suchergebnis weitergeleitet werden (die Suche wird erstellt und Sie erhalten eine 201 mit 2 Sekunden später wird dieses Ergebnis möglicherweise aus dem Speicher gelöscht und muss neu generiert werden. Keine Notwendigkeit zur Langzeitlagerung.Dies ist eine alte Antwort, aber ich kann immer noch ein wenig zur Diskussion beitragen. Ich habe sehr oft ein Missverständnis von REST, RESTful und Architecture beobachtet. RESTful erwähnt niemals etwas über NICHT-Gebäudesuche, es gibt nichts im RESTful über Architektur, es sind eine Reihe von Designprinzipien oder -kriterien.
Um eine Suche besser zu beschreiben, müssen wir über eine bestimmte Architektur sprechen, und die, die besser passt, ist die ressourcenorientierte Architektur (Resource Oriented Architecture, ROA).
In RESTful gibt es Prinzipien zum Entwerfen. Idempotent bedeutet nicht, dass sich das Ergebnis nicht ändern kann, wie ich in einigen Antworten gelesen habe. Es bedeutet, dass das Ergebnis einer unabhängigen Anforderung nicht davon abhängt, wie oft ausgeführt wird. Es kann sich ändern. Stellen wir uns vor, ich aktualisiere eine Datenbank, die Daten enthält, die von einer RESTful-API bereitgestellt werden, fortlaufend. Das Ausführen desselben GET kann das Ergebnis ändern, hängt jedoch nicht davon ab, wie oft es ausgeführt wurde. Wenn ich in der Lage bin, die Welt einzufrieren, bedeutet dies, dass es keinen Status, keine Transformation oder irgendetwas im Service gibt, wenn ich die Ressource anfordere, die zu einem anderen Ergebnis führt.
In einer ressourcenorientierten Architektur (kurz ROA) konzentrieren wir uns auf die Ressource, die viele Dinge sein kann:
Was es in Bezug auf die Ressource einzigartig macht, ist die Adressierbarkeit, was bedeutet, dass es nur einen URI hat
Auf diese Weise passt die Suche unter Berücksichtigung des ROA perfekt in RESTful . Wir müssen GET verwenden, da ich davon ausgehe, dass es sich bei Ihrer Suche um eine normale Suche handelt und sie nichts ändert. Sie ist daher idempotent (auch wenn sie abhängig von den neu hinzugefügten Elementen unterschiedliche Werte zurückgibt). In dieser Hinsicht gibt es Verwirrung, da ich mich an RESTful und nicht an ROA halten kann. Das bedeutet, dass ich einem Muster folgen kann, das eine Suche erstellt und verschiedene Dinge mit denselben Parametern zurückgibt, da ich nicht das Adressierbarkeitsprinzip von ROA verwende. Wie ist das? Wenn Sie die Suchfilter im Hauptteil oder im Header senden, ist die Ressource nicht ADRESSIERBAR.
Sie finden die Prinzipien von Was genau und URI im W3-Originaldokument:
https://www.w3.org/DesignIssues/Axioms
Jede URL in dieser Architektur muss selbsterklärend sein. Wenn Sie die Prinzipien befolgen, um alle Elemente in der URI zu adressieren, bedeutet dies, dass Sie / (Schrägstrich) verwenden können, um die von Ihnen benötigten Elemente oder Abfrageparameter zu trennen. Wir wissen, dass es Einschränkungen gibt, aber dies ist das Architekturmuster.
Nach dem ROA-Muster in RESTful ist eine Suche nicht mehr als jede andere Ressource. Der einzige Unterschied besteht darin, dass die Ressourcen aus einer Berechnung stammen und nicht aus einer direkten Beziehung zum Objekt selbst. Basierend auf dem Prinzip konnte ich einen einfachen Rechenservice nach folgendem Muster ansprechen und erhalten:
http://myapi.com/sum/1/2
Wenn Summe, 1 und 2 geändert werden können, das Ergebnis der Berechnung jedoch eindeutig und adressierbar ist, erhalte ich bei jedem Aufruf mit denselben Parametern dieselben Informationen und es ändert sich nichts am Dienst. Die resouce / sum / 1/2 und / substract / 5/4 halten sich perfekt an die Prinzipien.
quelle
GET ist in Ordnung, wenn Sie eine statische Auflistung haben, die für einen URI immer die gleichen Ergebnisse (Darstellung) zurückgibt. Dies bedeutet auch, dass die Daten, die diese Darstellungen erzeugen, niemals geändert werden. Die Quelle ist eine schreibgeschützte Datenbank.
Wenn GET unterschiedliche Ergebnisse für ein und denselben URI zurückgibt, verstößt dies gegen Idempotenz / Sicherheit und das CoolURI-Prinzip und ist folglich nicht REST-konform . Es ist möglich, dass idempotente Verben in eine Datenbank geschrieben werden, sie dürfen jedoch niemals die Darstellung beeinflussen.
Eine allgemeine Suche beginnt mit einer POST-Anforderung, die einen Verweis auf das Ergebnis zurückgibt. Es generiert das Ergebnis (es ist neu und kann mit einem nachfolgenden GET abgerufen werden). Dieses Ergebnis kann natürlich hierarchisch sein (weitere Verweise mit URIs, die Sie abrufen können) und Elemente früherer Suchvorgänge wiederverwenden, wenn dies für die Anwendung sinnvoll ist.
Ich weiß übrigens, dass die Leute das anders machen. Sie müssen mir nicht erklären, wie bequem es sein kann, REST zu verletzen.
quelle