577 Stimmen

Wie gestaltet man eine RESTful-Suche/Filterung?

Ich bin gerade dabei, eine RESTful API in PHP zu entwerfen und zu implementieren. Allerdings ist es mir nicht gelungen, meinen ursprünglichen Entwurf zu implementieren.

GET /users # list of users
GET /user/1 # get user with id 1
POST /user # create new user
PUT /user/1 # modify user with id 1
DELETE /user/1 # delete user with id 1

So weit, so normal, nicht wahr?

Mein Problem ist der erste Punkt GET /users . Ich habe in Erwägung gezogen, Parameter im Anfragetext zu senden, um die Liste zu filtern. Der Grund dafür ist, dass ich in der Lage sein möchte, komplexe Filter zu spezifizieren, ohne eine super lange URL zu erhalten, wie z. B.:

GET /users?parameter1=value1&parameter2=value2&parameter3=value3&parameter4=value4

Stattdessen wollte ich etwas haben wie:

GET /users
# Request body:
{
    "parameter1": "value1",
    "parameter2": "value2",
    "parameter3": "value3",
    "parameter4": "value4"
}

die viel besser lesbar ist und Ihnen großartige Möglichkeiten bietet, komplexe Filter zu setzen.

Wie auch immer, file_get_contents('php://input') nicht den Request Body für GET Anfragen. Ich habe auch versucht http_get_request_body() aber das Shared Hosting, das ich benutze, hat keine pecl_http . Ich bin mir nicht sicher, ob es überhaupt etwas gebracht hätte.

Ich fand diese Frage und erkannte, dass GET wahrscheinlich keinen Request Body haben sollte. Es war nicht ganz schlüssig, aber sie rieten davon ab.

Jetzt bin ich nicht sicher, was ich tun soll. Wie entwirft man eine RESTful-Such-/Filterungsfunktion?

Ich nehme an, ich könnte die POST aber das scheint nicht sehr RESTful zu sein.

471voto

Jason Harrelson Punkte 5325

Die beste Art und Weise, eine RESTful-Suche zu implementieren, besteht darin, die Suche selbst als eine Ressource zu betrachten. Dann können Sie das Verb POST verwenden, weil Sie eine Suche erstellen. Sie müssen nicht buchstäblich etwas in einer Datenbank erstellen, um POST verwenden zu können.

Zum Beispiel:

Accept: application/json
Content-Type: application/json
POST http://example.com/people/searches
{
  "terms": {
    "ssn": "123456789"
  },
  "order": { ... },
  ...
}

Sie erstellen eine Suche vom Standpunkt des Benutzers aus. Die Details der Implementierung sind dabei irrelevant. Einige RESTful APIs benötigen möglicherweise nicht einmal Persistenz. Das ist ein Implementierungsdetail.

213voto

jfcorugedo Punkte 8833

Wenn Sie den Request Body in einer GET-Anfrage verwenden, verstoßen Sie gegen das REST-Prinzip, da Ihre GET-Anfrage nicht in den Cache aufgenommen werden kann, da das Cache-System nur die URL verwendet.

Schlimmer noch: Ihre URL kann nicht mit einem Lesezeichen versehen werden, weil die URL nicht alle Informationen enthält, die erforderlich sind, um den Benutzer auf diese Seite weiterzuleiten.

Verwenden Sie URL- oder Query-Parameter anstelle von Request-Body-Parametern, z. B.:

/myapp?var1=xxxx&var2=xxxx
/myapp;var1=xxxx/resource;var2=xxxx 

Der HTTP RFC 7231 besagt, dass:

Eine Nutzlast innerhalb einer GET-Anforderungsnachricht hat keine definierte Semantik; das Senden eines Nutzlastkörpers bei einer GET-Anforderung könnte dazu führen, dass einige bestehende Implementierungen die Anforderung zurückweisen.

Weitere Informationen finden Sie unter aquí .

112voto

Opal Punkte 77538

Es scheint, dass das Filtern/Suchen von Ressourcen auf eine RESTful Weise implementiert werden kann. Die Idee ist die Einführung eines neuen Endpunkts namens /filters/ o /api/filters/ .

Verwendung dieses Endpunkts Filter kann als Ressource betrachtet werden und wird daher über POST Methode. Auf diese Weise können natürlich auch alle Parameter in body übertragen und komplexe Such-/Filterstrukturen erstellt werden.

Nach der Erstellung eines solchen Filters gibt es zwei Möglichkeiten, das Such-/Filterergebnis zu erhalten.

  1. Es wird eine neue Ressource mit eindeutiger ID zurückgegeben, zusammen mit 201 Created Statuscode. Mit dieser ID wird dann eine GET Anfrage kann gestellt werden an /api/users/ mögen:

    GET /api/users/?filterId=1234-abcd
  2. Nach der Erstellung eines neuen Filters über POST antwortet er nicht mit 201 Created sondern sofort mit 303 SeeOther zusammen mit Location Header, der auf /api/users/?filterId=1234-abcd . Diese Umleitung wird automatisch über die zugrunde liegende Bibliothek abgewickelt.

In beiden Szenarien müssen zwei Anfragen gestellt werden, um die gefilterten Ergebnisse zu erhalten - dies kann als Nachteil angesehen werden, insbesondere für mobile Anwendungen. Für mobile Anwendungen würde ich eine einzelne POST Aufruf an /api/users/filter/ .

Wie kann man erstellte Filter behalten?

Sie können in der DB gespeichert und zu einem späteren Zeitpunkt verwendet werden. Sie können auch in einem temporären Speicher wie z.B. Redis gespeichert werden und haben eine TTL, nach der sie ablaufen und entfernt werden.

Was sind die Vorteile dieser Idee?

Filter, gefilterte Ergebnisse sind zwischenspeicherbar und können sogar mit Lesezeichen versehen werden.

21voto

Daff Punkte 42755

Ich denke, Sie sollten Request-Parameter verwenden, aber nur, solange es keinen geeigneten HTTP-Header gibt, um das zu erreichen, was Sie tun wollen. Die HTTP-Spezifikation sagt nicht ausdrücklich, dass GET keinen Körper haben kann. Allerdings dieses Papier Staaten:

Wenn die GET-Methode konventionsgemäß alle Informationen, die zur Identifizierung die Ressource zu identifizieren, im dem URI kodiert. Es gibt keine Konvention in HTTP/1.1 für eine sichere Interaktion (z.B., Abruf), bei der der Client dem Server Daten an den Server in einer HTTP-Entität Body und nicht im Abfrageteil einer einer URI. Das bedeutet, dass für sichere Operationen können die URIs lang sein.

12voto

the-a-train Punkte 1083

Da ich eine laravel/php Backend tendiere ich zu so etwas wie diesem:

/resource?filters[status_id]=1&filters[city]=Sydney&page=2&include=relatedResource

PHP wandelt automatisch [] Parameter in ein Array, so dass ich in diesem Beispiel am Ende eine $filter Variable, die ein Array/Objekt von Filtern enthält, zusammen mit einer Seite und allen zugehörigen Ressourcen, die ich eifrig laden möchte.

Wenn Sie eine andere Sprache verwenden, könnte dies immer noch eine gute Konvention sein, und Sie können einen Parser erstellen, um die [] zu einem Array.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X