Wie passen Suchvorgänge in eine RESTful-Schnittstelle?

137

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 todomain/Job/{id}/
  • Stellenanzeige erstellen
    • POST zudomain/Job/
  • Stellenanzeige aktualisieren
    • PUT todomain/Job/
  • Stellenanzeige löschen
    • LÖSCHEN bisdomain/Job/

"Get All Jobs" ist auch einfach:

  • GET todomain/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 todomain/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 zudomain/Jobs/

Aber semantisch ist das eine Anweisung, eine Sammlung zu erstellen.

Sie können dies auch als Erstellung einer Suche ausdrücken:

  • POST zudomain/Jobs/Search/

oder (wie von burninggramma unten vorgeschlagen)

  • POST zudomain/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?

Rob Baillie
quelle
3
Ich habe oft die Absicht, GET zu verwenden domain/Jobs?keyword={keyword}. Das funktioniert gut für mich :) Ich hoffe, dass das SEARCHVerb zum Standard wird. programmers.stackexchange.com/questions/233158/…
Knerd
Ja, ich sehe, dass es für ein einfaches Beispiel kein Problem gibt. Aber in dem Tool, das wir erstellen, ist es eigentlich nicht so unglaublich, dass wir eine komplexe Suche haben, die zu einer GET-Zeichenfolge führt, die länger als 2000 Zeichen ist. Was dann?
Rob Baillie
Eigentlich ein sehr guter Punkt. Was ist mit der Angabe einer Komprimierungstechnologie?
Knerd
2
GET with a body ist in der HTTP-Spezifikation zulässig, wird möglicherweise von der Middleware unterstützt (manchmal auch nicht);) und wird aus praktischen Gründen nicht bevorzugt. Dies wird regelmäßig bei Stackexchange angezeigt. stackoverflow.com/questions/978061/http-get-with-request-body
Rob
2
Am Ende ließ ich POST JobSearch eine tatsächliche Sucheinheit erstellen und eine jobSearchId zurückgeben. Dann liefert GET jobs? JobSearch = jobSearchId die eigentliche Auftragserfassung.
Cerad

Antworten:

93

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 .

p1100i
quelle
4
Zur Verdeutlichung soll sich diese Frage auf das Design von Webdiensten beziehen, nicht auf das Design von Websites. Während das Browserverhalten für den weiteren Umfang der Frageinterpretation von Interesse ist, hat es im beschriebenen speziellen Fall keine Konsequenzen. (Interessanter Punkt).
Rob Baillie
@ RobBaillie Ye der Browser war nur ein Anwendungsfall. Ich wollte die Tatsache zum Ausdruck bringen, dass Ihre Suche insgesamt durch eine URL-Zeichenfolge dargestellt wird. Das hat viel Komfort in der Benutzerfreundlichkeit zusammen mit anderen Punkten später in der Antwort.
p1100i
In Punkt b, ist dies eine einfache Variation meiner eigenen Verweis auf eine POST an domain/Jobs/Search/, vielleicht mit domain/JobsSearch/stattdessen oder meintest du etwas anderes? Könntest Du das erläutern?
Rob Baillie
7
Warum habe ich den Eindruck, dass REST eher Teil des Problems als Teil der Lösung ist?
JensG
1
"GET-Anforderung sollte nichts in Ihrer Anwendung ändern (idempotent)", während GET idempotent ist, ist das relevante Wort hier " sicher ". Idempotent bedeutet, dass das zweimalige Abrufen einer Ressource dasselbe ist wie das einmalige Abrufen dieser Ressource. PUT ist zum Beispiel auch idempotent, aber nicht sicher.
Jasmijn
12

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.

dietbuddha
quelle
1
Da REST die zugrunde liegende Implementierung abstrahieren soll (z. B. - eine Ressource ist nicht unbedingt eine Zeile in einer Datenbank oder eine Datei auf einer Festplatte, sondern könnte alles sein ), weiß ich nicht, dass es unbedingt Sinn macht, POST zu verwenden GET, wenn es um die Ausführung von SQL-Joins geht. Angenommen, Sie haben einen Schultisch und einen Schultisch und möchten eine Klasse (eine Schule, mehrere Kinder). Sie könnten leicht eine virtuelle Ressource definieren und GET /class?queryParams. Aus der Sicht eines Benutzers war die "Klasse" immer eine Sache und Sie mussten keine seltsamen SQL-Joins ausführen.
Stevendesu
Es gibt keinen Unterschied zwischen "Filtern" und "Suchen".
Nicholas Shanks
1
Ja, ein Filter basiert auf vorhandenen Feldern. Eine Suche kann viel komplexere Muster enthalten, Felder kombinieren, angrenzende Werte berechnen usw.
user13796
@stevendesu genau, deshalb benutze ich POST für beide (eine Suche erstellen) :-)
ymajoros
@ymajoros Sofern Sie die Suchbegriffe und die Ergebnisse der Suche nicht irgendwo speichern, weiß ich nicht, dass POST semantisch sinnvoll ist. Wenn Sie eine Suche durchführen, bei der Sie Informationen anfordern, geben Sie keine neuen Informationen an, die an keiner Stelle gespeichert werden sollen.
Stevendesu
10

In REST ist die Ressourcendefinition sehr breit. Es ist wirklich so, wie Sie einige Daten bündeln möchten.

  • Es ist nützlich, sich eine Suchressource als Sammlungsressource vorzustellen. Die Abfrageparameter, die manchmal als durchsuchbarer Teil des URI bezeichnet werden, beschränken die Ressource auf die Elemente, an denen der Client interessiert ist.

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.)

  • Da die Ressource, nach der Sie in Ihrem Beispiel suchen, die Jobsammlung ist, ist es sinnvoll, mit zu suchen

GET site / jobs? Type = blah & location = here & etc = etc

(zurück) {jobs: [{job: ...}]}

Verwenden Sie dann POST, das heißt das Append- oder Prozessverb, um dieser Sammlung neue Elemente hinzuzufügen:

POST-Site / Jobs

{Job: ...}

  • Beachten Sie, dass es für das jobObjekt 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

Standort / Arbeitsplätze

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.)

rauben
quelle
Es ist eine interessante Idee - ich hätte nicht in Betracht gezogen, die Nutzlast zur Unterscheidung zu verwenden. Es scheint fast ein wenig hinterhältig! Aber ich denke, das URI-Schema enthält eigentlich keine Verben - es ist der Anfragetyp, der das Verb definiert. Möglicherweise ist die Nutzlast semantisch näher am Anforderungstyp als der URI. Das einzige Problem ist - Ist es für einen Benutzer der API transparent?
Rob Baillie
In Bezug auf die Implementierung (wir verwenden Node und Express) kann dies bedeuten, dass routedie Auswahl der Verarbeitung nicht wirklich bewältigt werden kann. Das müsste ich mir ansehen ...
Rob Baillie
Ich habe das gleiche Bauchgefühl, dass die Trennung durch URI sauberer erscheint. Ich gehe irgendwie hin und her; Es ist ein Urteilsspruch. Die Semantik von HTTP würde es jedoch ermöglichen, es in den Körper zu setzen. Ich möchte sagen, dass REST dem World Wide Web nachempfunden ist und das WWW mit GET und POST erstellt wurde.
Rob
8

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:

/users?$select=Id,Name$filter=endswith(Name, 'Smith')

Sie können auch mit $skipund $topund 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.

Trevor Pilley
quelle
6
Eine interessante Verbindung und ein Blick wert, aber löst es das grundsätzliche Problem beschrieben, die GET - Anfragen nicht mehr als 2000 Zeichen in dem Query - String unterstützen, und es ist durchaus möglich , dass die Abfrage könnte als dies weit mehr sein?
Rob Baillie
@RobBaillie Ich glaube nicht, da es immer noch ein GET-Aufruf mit einer Abfragezeichenfolge ist. Ich würde empfehlen, OData zu verwenden, wo immer Sie können, da dies ein Standard für die Abfrage von Webdatenquellen ist und die Abfrage so komplex sein muss, dass Sie sie in eine Abfrage mit 2000 Zeichen nicht einpassen können. Erstellen Sie eine bestimmte Abfrage Endpunkt, zu dem Sie einen GET-Anruf tätigen
Trevor Pilley
Können Sie Ihren Ansatz für einen "bestimmten Endpunkt, zu dem Sie einen GET-Aufruf tätigen" erläutern? Wie könnten Sie sich vorstellen, dass dieser Endpunkt aussehen würde?
Rob Baillie
@RobBaillie sicher - wieder bin ich nicht sicher, welche Technologie Sie verwenden, aber in ASP.NET würde ich einen bestimmten Controller namens JobsNearMeAddedInTheLast7Daysoder 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 .
Trevor Pilley
1
Aha. Ein weiterer interessanter Gedanke, der wahrscheinlich einige Beine hat, obwohl ich nicht sicher bin, ob dies in meinem speziellen Fall helfen würde - facettierte Suche mit vielen Facettentypen und vielen möglichen Facettenwerten
Rob Baillie
5

Ein zu berücksichtigender Ansatz besteht darin, die Menge möglicher Abfragen als Sammlungsressource zu behandeln, z /jobs/filters.

POSTAnfragen 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. Nachfolgende GETAnforderungen 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 GETAnforderung 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 /jobsRessource 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, /jobssollte die Implementierung bei Verwendung von Abfrageparametern für die Ressource intern eine Filterressource erstellen / wiederverwenden und einen 302oder 303-Status zurückgeben, der die URL in Form von angibt , um die Cachefreundlichkeit zwischen den beiden Filtertypen zu gewährleisten /jobs?filter=12345.

pgraham
quelle
Meine erste Reaktion darauf ist, dass es sich zwar um gute Informationen handelt, es sich jedoch nur um eine Variation der Antwort von @burninggramma handelt. Im Wesentlichen ist es "eine neue Entität namens Filter / Suche erstellen, aufrufen, um sie zu erstellen und dann aufrufen, um sie abzurufen". Die Variation ist, dass der Aufruf zum Abrufen eher einem Aufruf zum Anwenden auf eine Sammlung ähnelt. Interessant. Allerdings haben sowohl Ihre als auch die Antwort von burninggramma das gleiche Problem - ich habe keine Lust, die Filter zu erstellen. Es wird eine große Anzahl von ihnen geben, und sie müssen nur gespeichert werden, um eine REST-konforme Implementierung zu gewährleisten.
Rob Baillie
2
Abfrageparameter sind natürlich die beste Lösung. Bei Ihrer Frage geht es jedoch speziell darum, wie mit Filterdefinitionen umgegangen wird, die länger sind als die von einigen Servern auferlegten URLs. Um das Längenlimit zu umgehen, müssen Sie entweder die Abfragezeichenfolge irgendwie komprimieren oder eine Anforderungsmethode verwenden, die die Angabe eines Körpers beliebiger Länge unterstützt. Wenn Sie Filter nicht als Ressource behandeln möchten, unterstützen Sie einfach eine nicht ruhende Schnittstelle, in der Filterdefinitionen POST-fähig sind. Sie verlieren die Cachefähigkeit, aber wenn Ihre Daten flüchtig genug sind, würde das Caching ohnehin keinen Nutzen bringen.
pgraham
Sie können die Notwendigkeit, Filter zu speichern, überwinden, indem Sie sie einfach ... nicht speichern. Nichts an REST garantiert, dass es dauerhaft ist. Sie können eine Anfrage für GET /jobs/37ein 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 Sie POST /searchesund 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.
Stevendesu
5

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.

Per Definition ist eine Ressource alles, was wichtig ist, um als eigenständige Sache referenziert zu werden.

In einer ressourcenorientierten Architektur (kurz ROA) konzentrieren wir uns auf die Ressource, die viele Dinge sein kann:

  • Eine Version eines Dokuments
  • Die zuletzt aktualisierte Version des Dokuments
  • Ein Ergebnis einer Suche
  • Eine Liste von Objekten
  • Der erste Artikel, den ich bei einem E-Commerce gekauft habe

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.

Maximiliano Rios
quelle
3

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.

Martin Sugioarto
quelle
Aaaaaaaah - so soll es funktionieren! Vielen Dank!
Rob Baillie
1
Idempotenz bedeutet nicht, dass es immer genau dasselbe zurückgeben muss, es muss dasselbe zurückgeben, wenn sich NICHTS ändert. Die Suche kann als Ergebnis einer Berechnung betrachtet werden und ist selbst eine Ressource.
Maximiliano Rios
Idempotenz bedeutet eigentlich, dass das Ergebnis gleich bleibt. Sie können und es ist praktikabel, die Cache-Steuerung zu verwenden. Und Sie können natürlich DELETE verwenden, das spätere GETs stört. Wenn ein Agent jedoch Kenntnisse über die Funktionsweise der Anwendung behalten muss, ist dies nicht mehr REST-fähig. Oben habe ich über die extremste Idee von REST gesprochen. In der Praxis können Menschen viele Aspekte davon verletzen. Sie zahlen den Preis, wenn Caches nicht mehr effizient cachen.
Martin Sugioarto
"Idempotenz bedeutet eigentlich, dass das Ergebnis gleich bleibt." ... nach der Anfrage. Ich glaube, der Punkt ist, dass die Anfrage die Daten nicht ändert.
AndreiMotinga