it-swarm.com.de

REST URL-Design für Operationen mit mehr als oder weniger als

Ich habe einige Schwierigkeiten beim Entwerfen einer URL für einen Ruhedienst, der Anfragen für Kunden basierend auf Seitenumlagerung als eine Art von Operation oder als mehr oder weniger als Operatoren als eine andere Art von Operation behandeln kann. Zum Beispiel:

Seitennummerierung:

GET /customers/0/100

Damit erhalten Sie 100 Kunden für Seite 0.

Größer/Weniger als:

Ich brauche auch ein URL-Design, um Kunden zu erhalten, deren ID größer als n ist (z. B. 716). Wie würden Sie "größer als" oder "kleiner als" in eine URL integrieren? Ich muss bedenken, dass die Zeichen ">" und "<" in URLs illegal sind. Ich finde dieses URL-Design sieht merkwürdig aus:

GET /customers/greaterthan/716
GET /customers/lessthan/716

Ich kann keinen Bereich verwenden, da dies mit dem oben angegebenen Paginierungsmuster kollidieren würde und in keinem Fall eine Lösung von Nizza ist, z.

GET /customers/716/999999999999
GET /customers/0/716

Ich bin sicher, dass mir etwas fehlt, was offensichtlich ist - hat jemand eine bessere Lösung?

23
Vidar

Pagination , greaterthan und lessthan , klingt für mich wie ein Abfrageparameter, da Sie Ihre Ressource mit diesen Parametern abfragen. Also solltest du so etwas tun:

/Kunden? page = 1 oder
/Kunden? page = 1 & gt = 716 oder
/Kunden? page = 1 & gt = 716 & lt = 819  

Sie können sogar die Größe der Seite begrenzen:

/Kunden? page = 1 & gt = 716 & lt = 819 & maxpagesize = 100  

dabei steht gt für größer als (gleich wie bei xml-escaping) und lt steht für kleiner als.

28
Tarlog

Wenn Sie mehrere Parameter haben und einige Bedingungen für die einzelnen Parameter anwenden müssen, empfehle ich Ihnen, ein JSON-Objekt an params zu übergeben.

Stellen Sie sich vor, Sie möchten eine Bedingung für id und die page ausführen:

/customers?id={"lt": 100, "gt": 30}&page={"start": 1, "size": 10}

Es heißt, dass ich Kunden mit Id (s) kleiner als 100 und größer als 30 in der Seite 1 und Seitennummer haben möchte. von 10.

Wenn Sie also einfach eine andere Bedingung für andere Parameter anwenden möchten, können Sie dies folgendermaßen tun:

/customers?id={"lt": 100, "gt": 30}&children={"lt": 5, "gt": 2}&page={"start": 1, "size": 10}

und diese Abfrage bedeutet Kunden mit Id (s) kleiner als 100 und größer als 30, children kleiner als 5 und größer als 2 in der Seitennummer 1 mit Seitengröße von 10.

Ich empfehle Ihnen dringend, dieses Dokument zur Entwicklung der RESTful-API zu lesen: http://blog.luisrei.com/articles/rest.html

16

REST ist ein Architekturstil, der nicht als spezifisch für HTTP betrachtet werden sollte. Das Muster der URIs ist nicht das, was eine Architektur RESTful macht.

Wenn dies gesagt ist, möchten Sie wahrscheinlich Ihren URI so einrichten, dass diese Abfragen als Abfrageparameter am Ende der Zeichenfolge stehen, z.

/customers?min=0&max=76
7
pc1oad1etter

@Julio Faerman:

Nun, das Problem beginnt, wenn Sie mehrere Parameter erhalten. Stellen Sie sich die Abfragezeichenfolge für "Kunden älter als 18 und jünger als 60 mit mehr als zwei Kindern" vor.

Sie können beliebige Abfrageparameter definieren, wie zum Beispiel:

/customers?min-age=19&max-age=59&min-children=3

in meinem Beispiel sind min und max ganze Zahlen und sind inklusive. Sie können das ändern, wenn Sie möchten. Denken Sie daran, dass alles in der URI einen Teil des Ressourcenbezeichners darstellt. Meine persönliche Ansicht ist, dass Dinge nach dem ? den Klauseln im WHERE-Teil einer SQL-Abfrage entsprechen (plus ORDER BY und LIMIT, hier nicht gezeigt):

SELECT * FROM customers WHERE age>=19 AND age<=59 AND children>=3

Bearbeiten:
Anstelle der Präfixe min- und max- können Sie >, < (und möglicherweise !) als abschließendes Zeichen des Parameternamens zulassen. Daher haben Sie anstelle von min-age einen Parameter mit der Bezeichnung age>, der mit einem Wert kombiniert wird in der Abfragezeichenfolge sieht es aus wie age>=19 :-)
Natürlich können Sie diesen Trick nur verwenden, wenn der Vergleich ein Gleichheitszeichen enthält.

7
Nicholas Shanks

Nehmen wir an, Sie holen Ihre Serverprotokolle ab und nehmen an, dass Ihre Daten folgendermaßen aussehen:

{
    "protocol": "http",
    "Host": "example.domain.com",
    "path": "/apis/classified/server/logs",
    "method": "GET",
    "ip": "::ffff:127.0.0.1",
    "time": 1483066346338,
    "usingTime": 12,
    "status": 200,
    "headers": {
        "user-agent": "Mozilla/5.0 Chrome"
    }
}

Und Sie möchten auf diese Weise wo abfragen

  • protocol entspricht 'http'.
  • Host ist gleich 'example.domain.com' oder nicht gleich 'example.domain.me'.
  • path entspricht '/apis/classified/server/logs' oder ähnlichen /*classified\/server*/.
  • method ist gleich 'DELETE' oder nicht gleich 'GET' oder in ['POST', 'PUT', 'DELETE'].
  • ip ist gleich '127.0.0.1' oder nicht gleich '127.0.0.1'.
  • usingTime ist größer als 3500 oder größer als oder gleich 1500 und kleiner als oder gleich 3500.
  • status ist gleich 404 oder nicht gleich 200 oder ist größer als oder gleich 400 und ist kleiner als 500.
  • headers.user-agent mag /*chrome*/i.

Hier gehen die Routen so:

  • /apis/classified/server/logs?path=/apis/classfied
  • /apis/classified/server/logs?path.regex=*classfied*
  • /apis/classified/server/logs?method.ne=GET
  • /apis/classified/server/logs?method=POST&method=PATCH&method=PUT
  • /apis/classified/server/logs?usingTime.gte=1500&usingTime.lte=2500
  • /apis/classified/server/logs?headers.user-agent.regex=*chrome*

Wenn Sie express.js als Server verwenden, wird Ihre Anfrage wie folgt strukturiert:

  • {"path": "/apis/classfied"}
  • {"path": {"regex": "*classfied*"}}
  • {"method": "DELETE"}
  • {"method": ["GET","POST","PUT"]}
  • {"usingTime": {"gte": "1500","lte": "2500"}} (lte: ist kleiner oder gleich)
  • {"status": {"ne": "200"}}} (ne: ist nicht gleich)
  • {"path": {"regex": "*classfied*"}}
  • {"headers": {"user-agent": {"regex": "*chrome*", "flag": "i"}}}

Und Sie werden eine Menge von if-else verwenden, um Ihre mongoose-Abfragemethode oder SQL-Zeichenfolge zu erstellen.

2
Fisher

Ich würde es als Bereich implementieren, und wenn eine Seite offen ist, füllen Sie es einfach nicht.

GET /customers/16-
GET /customers/-716

Wenn Sie alle Kunden anfordern, fügen Sie nicht alle hinzu, lassen Sie sie einfach leer

GET /customers

Oder verwenden Sie - wenn Sie Ihre Nummer/Ihren Code benötigen - Folgendes:

GET /customers/16/
GET /customers//716
GET /customers/16/716

Sie können die Schrägstriche umgehen, wenn sie Teil der Nummer sind.

1
RobAu

WARNUNG: Lesen Sie den folgenden Haftungsausschluss

Ich weiß nicht, ob diese Frage mit c # zusammenhängt. Wenn Sie jedoch linq für Ihre Abfragen auf der Serverseite verwenden, habe ich einen anderen Vorschlag:

GET /customers?filter=CustomerNo>=16 AND CustomerNo<=716

Dann auf der Serverseite:

using System.Linq.Dynamic;

var filteredCustomers = myCustomerTable.Where(filter);

Ich denke, dies sollte die flexibelste Lösung von allen sein.


WARNING hinzugefügt 19. Januar 2017 Ich habe gerade erfahren, dass es einen Code-Injection-Exploit für Dynamic Linq gibt. Das obige Beispiel eröffnet die Möglichkeit, dass der Client die Codeausführung auf dem Server starten kann.

0
user3414239

Einige REST-basierte Standards bieten adäquate Ansätze für dieses Problem. Zum Beispiel https://www.hl7.org/fhir/stu3/search.html

Ihr Problem kann folgendermaßen gelöst werden: GET /customers?id=ge500&id=lt1000

Außerdem gibt es OData , das weitaus mehr interoperabel ist als jeder Industriestandard. Und es schlägt diesen Stil vor: GET /customers?$filter=id ge 500 and id lt 1000

0
astef