Wie kann eine komplexe RESTful-Suchmethode ordnungsgemäß durchgeführt werden?

44

Nach den REST-Grundsätzen möchte ich eine GET-Methode für meine API erstellen, die anhand einiger Kriterien eine Suche durchführt und die Ergebnisse an den Client zurückgibt. Das Problem ist, dass die Kriterien bis zu 14 Parameter haben können, von denen einer eine Liste komplexer Objekte ist.

  • Ich weiß nicht einmal, ob es möglich ist, diese komplexen Objekte in URL-Parameter zu kodieren / zu dekodieren.

  • Ich habe nicht berechnet, wie lange die URL dauern kann, bin mir aber sicher, dass sie groß genug ist und möglicherweise die maximale URL-Länge erreicht.

Außerdem sollte die Suche die Ergebnisse in "Echtzeit" anzeigen. Ich meine, jedes Mal, wenn der Benutzer etwas in der Suchmaske ändert, sollte er in der Lage sein, die neuen Ergebnisse zu sehen, ohne die Schaltfläche "Suchen" zu drücken.

Könnten Sie mir diese Punkte erläutern und was würden Sie raten, um eine erholsame Suchmethode mit vielen Parametern zu erstellen?

anat0lius
quelle
3
Abgesehen davon (ich stelle fest, dass keine der beiden Antworten zum Zeitpunkt des Schreibens den Echtzeit-Teil erwähnt), sollten Echtzeit-Suchvorgänge in der Regel nur die aktualisierte Anfrage immer und immer wieder senden. Zum Beispiel, während Sie tippen, dann würden Sie Anfragen für Sachen wie das Senden search?q=t, search?q=te, search?q=test, und so weiter. Überlegen Sie, wie oft die Abfrage gesendet wird, um den Server nicht zu beschädigen. Alternativ können Sie auch viele Informationen zurückgeben und clientseitig filtern. Das funktioniert gut, wenn der Benutzer breite Kategorien eingibt, die die Dinge stark einschränken können.
Kat
2
Stellen Sie unabhängig von der Lösung sicher, dass Sie Daten in einem technologieneutralen Format austauschen. Verwenden Sie also keine interne Darstellung, da sonst das Schreiben von Clients für Ihre API schwieriger wird.
Kwebble
Abhängig von Ihren Bedürfnissen könnte diese Bibliothek den Job machen: github.com/jirutka/rsql-parser . Es hat eine JPA-Erweiterung, wenn Sie JPA verwenden, oder Sie können Ihren eigenen Besucher schreiben, um ihn der API Ihrer Suchmaschine zuzuordnen. Und Sie können Ihren eigenen Operator hinzufügen.
Walfrat

Antworten:

54

Bevor Sie meine Antwort lesen, möchte ich sagen, dass ich mit @Neil einverstanden bin. Wir müssen unsere Schlachten auswählen. Wir wollen normalerweise unser Bestes geben, aber manchmal gibt es zu wenig Raum für Diskussionen und wir müssen Entscheidungen gegen unseren Willen treffen.

Wie auch immer, in Neils Antwort vermisse ich noch eine Sache. Dokumentation . Nur um sicherzustellen, dass Entwickler wissen, dass POST-Anforderungen /searchsicher sind.

Das gesagt.

1. Gib GET eine Chance

Betrachten Sie zuerst die GETOption. Überprüfen Sie die maximale Länge dieser Fragen- URL . Bewerten Sie, ob Ihre längste Abfragezeichenfolge länger als 2000 Zeichen ist. Wenn dies nicht der Fall ist und Sie dies nicht erwarten, gehen Sie mit GET. Es mag hässlich erscheinen, aber zumindest können Sie die URL mit einem Lesezeichen versehen und natürlich hat es alle Vorteile, die sich aus der Semantik der Methode ergeben (Idempotenz, Sicherheit und Caching).

1.1 Versuchen Sie, die Abfragezeichenfolge zu codieren

Zum Beispiel in Base 64. Auch JavaScript unterstützt Base 64-Codierungen .

So funktioniert es:

  1. Erstellen Sie den JSON mit allen Filtern und normalisieren Sie ihn.
  2. Analysiere es in einen String
  3. Codiere es
  4. Senden Sie den verschlüsselten JSON als Request param ( /search?q=SGVsbG8gV29ybGQh....).
  5. Dekodieren Sie serverseitig den Parameter q .
  6. Deserialisieren Sie die JSON-Zeichenfolge

Machen Sie vorher den längsten möglichen JSON-String, kodieren Sie ihn und nehmen Sie die Länge. Bewerten Sie, ob die codierte Zeichenfolge in die URL passt. Ich habe das folgende Snippet auf Fiddle.js implementiert, damit Sie es testen können. (Ich hoffe es funktioniert immer noch) 1

Base-64-Codierungen sind deterministisch und reversibel, sodass Kollisionen ausgeschlossen sind.

Mit verschlüsselten Abfragen können wir auch Suchvorgänge in der Datenbank speichern, die URL mit einem Lesezeichen versehen, Links freigeben usw. Und natürlich müssen wir die Zeichenfolge nicht entschlüsseln / entschlüsseln.

1.2 Versuchen Sie es mit Aliasen

Als ich diesen Blog über das Entwerfen von REST-APIs las, fiel mir eine weitere Alternative ein. Aliase für häufig gestellte Fragen .

Ich finde diese aus den nächsten Gründen interessant

  • Kürzen Sie die Länge der Abfragezeichenfolge. Es macht die API sauberer und benutzerfreundlicher

    GET / tickets /? Status = closed & closedAt = xxx vs GET / tickets / kürzlich geschlossen /

  • Kombinierbar mit mehr Aliasen oder mehr Anforderungsparametern.

    GET / tickets /? Status = closed & closedAt = xxx & within = 30min vs GET / tickets / recent -closed /? Within = 30min

  • Wir können Aliase mit codierten Abfragezeichenfolgen kombinieren

    GET / tickets /? Status = closed & closedAt = xxx & within = 30min vs GET / tickets / kürzlich geschlossen /? Q = SGVsbG8g ...


1: Ich habe JSON verwendet, aber wir könnten andere Formate verwenden, sobald wir es serverseitig deserialisieren können.

Laiv
quelle
2
Dies ist sowohl praktisch als auch richtig. Es ist auch erwähnenswert, dass es in den meisten Programmiersprachen trivial ist, einen Hash in eine Abfragezeichenfolge umzuwandeln, sodass es sehr einfach ist, mit einer GET-Aktion zu beginnen.
Aluan Haddad
1
Ich liebe Spring stackoverflow.com/questions/16942193/… Ich kann nicht glauben, dass es beim ersten Versuch funktioniert hat: D. Über die URL-Länge, ist weniger als 1k, obwohl wir noch die Spezifikationen iterieren müssen.
anat0lius
Dann geh mit GET. Der Einfachheit halber. Mit Spring MVC können Sie mit GET dasselbe Mapping erzielen. Suchen Sie nach Spring's WebArgumentResolver ;-)
Laiv
Base64 erhöht die Nutzlast um ca. 4/3. Während die Urlencodierung für Sonderzeichen 3/1 ergeben kann, behalten Abfragen mit meist sicheren Zeichen die gleiche Größe. Gibt es einen anderen Grund, base64 zu verwenden?
Villasv
Nicht wirklich. Ich mag (un) Escape-URLs einfach nicht. Das Übermaß an Nutzlast ist hier der Kompromiss. Es muss immer noch in die maximale Größe von GET pro Anfrage passen. Deshalb habe ich das Snippet gebaut. Für den Benutzer zu versuchen. Als ich die Antwort schrieb, priorisierte ich die Websemantik vor den Implementierungsdetails. Der springende Punkt der Antwort ist "versuchen Sie es weiter mit GET". Finden Sie Ihren Weg oder verwenden Sie eine dieser Methoden, die ich Ihnen teile.
Laiv,
13

Wenn Sie nur einen Hammer haben, sieht alles aus wie ein Nagel. Es scheint, dass das Problem darin besteht, dass Sie versuchen, eine Suchseite in eine REST-konforme zu verwandeln, und dies scheint kaum ein gängiges Muster für REST-konformes Design zu sein.

Gehen Sie einfach mit einer POST-Anfrage mit vom Benutzer angegebenen Parametern, um die benötigten Informationen aus dem Backend zu erhalten. Ich gehe davon aus, dass Sie nichts anderes tun müssen, als eine Suche durchzuführen. Es besteht also keine Chance, dass Sie diese Seite durchblättern müssen. Fügen Sie einfach ein / search am Ende Ihrer URL hinzu, damit Sie nicht in Konflikte mit Ihrer / users-Seite geraten, die RESTful wären .

Neil
quelle
2
@LiLou_: Für diese Anforderung gibt es nur zwei realistische Möglichkeiten: 1. Lesen Sie alle Daten in Ihr Front-End und filtern Sie dort. Dies kann bei der erforderlichen Speicherkapazität unzulässig sein. 2. Stellen Sie für jede Änderung der Suchkriterien eine neue Anfrage an den Server. Es spielt keine Rolle, ob es sich um eine POST- oder eine GET-Anforderung handelt, aber die damit verbundene Netzwerklatenz kann für das Gefühl des Benutzers, in Echtzeit aktualisiert zu werden, störend sein.
Bart van Ingen Schenau
2
Ich würde zustimmen, nicht zuzustimmen, POST bedeutet semantisch etwas anderes. Ich würde vorschlagen, mit dem GET zu gehen und alle Filterdaten im Abfrageparameter jetzt zu übergeben, wenn es zu viele Parameter gibt, dann ist es ein Fehler auf der Anwendungsebene.
CodeYogi
2
@CodeYogi Manchmal gibt der Kunde dir keinen Raum für Diskussionen. Ich habe Excel-ähnliche Ansichtsseiten mit jeweils 40-50 Spalten und einem eigenen Filter implementiert. Und natürlich sortierbar. Wie auch immer, es ist immer noch möglich mit GET, aber es scheint nicht zu modisch
Laiv
1
@Laiv In diesem Fall muss eine ernsthafte Diskussion stattfinden, da POST für die Änderung des Serverstatus gedacht ist. Die Anwendungsfälle wie diese sind keine Ausnahme und sollten daher ohne Hacks behandelt werden.
CodeYogi
2
In diesen Fällen ist die Dokumentation ein Muss. Ich habe ernsthafte Gespräche mit Kunden über die Benutzerfreundlichkeit ihrer Anwendungen geführt. Später hat sich gezeigt, dass ich Recht habe, weil der Endbenutzer mir zugestimmt hat. Manchmal muss man jedoch seine Schlachten auswählen.
Laiv
0

Es hängt ganz davon ab, welches API-Modell Sie verwenden: Als keines oder als Verb.

Wenn die API keine ist, möchten Sie möglicherweise eine Liste der Objekte wie folgt abrufen:

GET: /api/v1/objects

In diesem Fall müssen Sie Daten als Anforderungsparameter senden. Sie müssen Ihre Parameter also als eine flache Liste von Schlüsselwerten beschreiben:

GET: /api/v1/objects

key1 : val1
key2.key1 : val 21
key2.key2 : val 22
....

Einige Plattformen unterstützen benutzerdefinierte Parameter-Resolver (z. B. Spring MVC), und Sie können Parameter in ein Objekt konvertieren.

Mostafa
quelle