RESTful Möglichkeit, mehrere Elemente in einer Anfrage zu erstellen

122

Ich arbeite an einem kleinen Client-Server-Programm, um Bestellungen zu sammeln. Ich möchte dies auf eine "REST (ful) Weise" tun.

Was ich tun möchte ist:

Sammeln Sie alle Bestellpositionen (Produkt und Menge) und senden Sie die vollständige Bestellung an den Server

Im Moment sehe ich zwei Möglichkeiten, dies zu tun:

  1. Senden Sie jede Bestellposition an den Server: POST-Menge und Produkt-ID

Ich möchte dies eigentlich nicht tun, weil ich die Anzahl der Anforderungen an den Server begrenzen möchte, also Option 2:

  1. Sammeln Sie alle Bestellpositionen und senden Sie sie sofort an den Server.

Wie soll ich Option 2 implementieren? Ich habe folgende Ideen: Wickeln Sie alle Bestellzeilen in ein JSON-Objekt und senden Sie diese an den Server oder verwenden Sie ein Array, um die Bestellpositionen zu veröffentlichen.

Ist es eine gute Idee oder eine gute Praxis, Option 2 zu implementieren, und wenn ja, wie soll ich das tun?

Was ist eine gute Praxis?


quelle

Antworten:

74

Ich glaube, dass ein anderer korrekter Weg, dies zu erreichen, darin besteht, eine andere Ressource zu erstellen, die Ihre Ressourcensammlung darstellt. Stellen Sie sich zum Beispiel vor, wir haben einen Endpunkt wie /api/sheep/{id}und können POST /api/sheep, um eine Schafressource zu erstellen.

Wenn wir nun die Massenerstellung unterstützen möchten, sollten wir eine neue Herdenressource bei in Betracht ziehen /api/flock(oder /api/<your-resource>-collectionwenn Ihnen ein aussagekräftigerer Name fehlt). Denken Sie daran, dass Ressourcen nicht Ihrer Datenbank oder Ihren App-Modellen zugeordnet werden müssen . Dies ist ein weit verbreitetes Missverständnis.

Ressourcen sind eine übergeordnete Darstellung, die nicht mit Ihren Daten zusammenhängt. Das Bearbeiten einer Ressource kann erhebliche Nebenwirkungen haben, z. B. das Auslösen einer Warnung an einen Benutzer, das Aktualisieren anderer verwandter Daten, das Initiieren eines langlebigen Prozesses usw. Beispielsweise könnten wir ein Dateisystem oder sogar den Unix- psBefehl als REST-API zuordnen.

Ich denke, es ist sicher anzunehmen, dass der Betrieb einer Ressource auch die Schaffung mehrerer anderer Entitäten als Nebeneffekt bedeuten kann.

Miguelcobain
quelle
Ich bin damit einverstanden. Sie sollten das Konzept einer Sammlung Ihrer Ressource abstrahieren und diese wie eine Ressource behandeln. Dies gibt Ihnen auch in Zukunft mehr Flexibilität, wenn Sie mit Operationen usw. beginnen
möchten
Dies ist der richtige Ansatz. Dadurch wird die POST-Erfassungsanforderung nicht unterbrochen. Da wird es verwendet, um eine einzelne Entität zu buchen. Das Senden einer Massenanforderung mit einer "separaten Masseneinheit" ist der richtige Ansatz.
Sortierer
2
Ich mag es, wenn Sie einen API-Endpunkt so sehr mit Schafen und Herden benennen! Mit einem gewissen Grad an Abstraktion hat es fast einen biblischen Bezug: "Ich habe andere Schafe, die nicht von dieser Herde sind; ich muss sie auch bringen, und sie werden meine Stimme hören; und sie werden eine Herde mit einem Hirten." Johannes 10:16.
Evgeny
1
Interessanterweise empfehlen die Benutzer, die Pluralform (der Sammlung) in der URL zu verwenden, wenn Sie eine einzelne Ressource erstellen möchten, z. B.: Senden Sie einen POST an / api / books, um ein Buch zu erstellen. Aber wenn Sie dann 100 Bücher erstellen möchten (in einer einzigen Anfrage als json), unter welcher URL würden Sie die Sammlung von 100 Büchern veröffentlichen? Hier beginnt die Unruhe.
Code4kix
@ code4kix könnten Sie verwenden /api/book-group, /api/book-collectionoder etwas ähnliches.
Miguelcobain
46

Obwohl Massenoperationen (z. B. Batch-Erstellung) in vielen Systemen unerlässlich sind, werden sie vom RESTful-Architekturstil formal nicht berücksichtigt.

Ich habe festgestellt, dass das POSTEN einer Sammlung, wie Sie vorgeschlagen haben, grundsätzlich funktioniert. Es treten jedoch Probleme auf, wenn Sie als Antwort auf eine solche Anforderung Fehler melden müssen. Solche Probleme sind schlimmer, wenn mehrere Fehler aus unterschiedlichen Gründen auftreten oder wenn der Server keine Transaktionen unterstützt. Mein Vorschlag an Sie ist, dass es sich lohnt, 100 POST-Anforderungen an den Server zu senden, wenn kein Leistungsproblem vorliegt, z. B. wenn sich der Dienstanbieter im LAN befindet (nicht im WAN) oder wenn die Daten relativ klein sind. Halten Sie es einfach, beginnen Sie mit separaten Anforderungen und versuchen Sie zu optimieren, wenn Sie ein Leistungsproblem haben.

LiorH
quelle
3
Haben Sie selbst eine Lösung für Fehler bei der Stapelverarbeitung gefunden? Bei einer mobilen Verbindung werden 100 Post-Anfragen gesendet, um eine Seite wie eine schlechte Idee zu zeigen.
Thomas Ahle
Ich hänge die Fehler an ein Array an, leite den Benutzer zu einer 419 Conflict-Fehlerseite (und gebe diesen Fehler an den Client zurück) und zeige das Fehlerarray an. Siehe meine Antwort unten für weitere Details.
Eric Fuller
5
Das ist schwachsinn. Die Frage betrifft das Senden einer Bestellung für viele Artikel, die, wie viele gesagt haben, nur in der Entität einer POST-Anfrage erfolgen können. Wie der Server damit umgeht, ist eine ganz andere Sache. In diesem Fall sehe ich kein Problem darin, eine Bestellung zu erstellen, das zu füllen, was Sie für diese Bestellung können, und auch Details zu füllen, die nicht ausgeführt werden konnten. Auf diese Weise kann ein Benutzer seine Bestellung sehen und sehen, dass alle bis auf N Artikel zur Bestellung hinzugefügt wurden, einige jedoch nicht vorrätig waren oder das System nicht wusste, was zu tun ist. Eine andere einfachere, aber weniger benutzerfreundliche Option ist, alles abzulehnen
thecoshman
2
@thecoshman viel ändert sich in 3,25 Jahren. Sie sollten wahrscheinlich eine vollständig formulierte Antwort auf die Frage posten.
Dlamblin
3
@ Lamblin Ja, ich sollte wahrscheinlich eine Menge Dinge tun ... Ich werde es vielleicht
irgendwann schaffen
9

Facebook erklärt, wie das geht: https://developers.facebook.com/docs/graph-api/making-multiple-requests

Einfache Stapelanfragen

Die Batch-API nimmt ein Array von logischen HTTP-Anforderungen auf, die als JSON-Arrays dargestellt werden. Jede Anforderung verfügt über eine Methode (entsprechend der HTTP-Methode GET / PUT / POST / DELETE usw.), eine relative_url (den Teil der URL nach graph.facebook). com), optionales Header-Array (entsprechend HTTP-Headern) und ein optionaler Body (für POST- und PUT-Anforderungen). Die Stapel-API gibt ein Array von logischen HTTP-Antworten zurück, die als JSON-Arrays dargestellt werden. Jede Antwort verfügt über einen Statuscode, ein optionales Header-Array und einen optionalen Body (eine JSON-codierte Zeichenfolge).

rwitzel
quelle
1
Dies ist ein sehr interessanter Link, die vorgeschlagene Lösung scheint mir brauchbar. Bei StackOverflow wird als bevorzugte Antwort das Konzept der Lösung im Hauptteil einer Antwort erläutert, da sich Links ändern oder verschwinden können.
Jan Vlcinsky
7
Das ist wirklich die Art und Weise, wie Facebook es tut, nicht unbedingt RESTful, wie das OP gefragt hat
0cd
Ich denke, eine Batch-API (von Google, Facebook usw. - @PuneetArora) ist nützlicher, wenn mehrere nicht zusammenhängende Anforderungen zusammengefasst werden. Das Erstellen einer Anfrage, die ein Element erstellt, und das anschließende Gruppieren aller dieser Anforderungen zum Senden einer Sammlung von Elementen ist "Wahnsinn" (Einstein). Erstellen Sie einfach eine Anfrage, die eine Sammlung von Elementen übergibt.
tfmontague
8

Ihre Idee scheint mir gültig zu sein. Die Implementierung ist eine Frage Ihrer Präferenz. Sie können JSON oder nur Parameter für dieses Array ("order_lines []") verwenden und tun

POST /orders

Da Sie in einer einzigen Aktion (Reihenfolge und ihre Zeilen) mehr Ressourcen gleichzeitig erstellen, ist es wichtig, jede einzelne zu validieren und nur zu speichern, wenn alle die Validierung bestehen, d. H. Sie sollten es in einer Transaktion tun.

Milan Novota
quelle
6

Ich denke, es ist besser, separate Anfragen innerhalb einer einzigen Verbindung zu senden . Natürlich sollte Ihr Webserver dies unterstützen

zakovyrya
quelle
5

Ich habe in letzter Zeit tatsächlich damit gerungen, und hier ist, worauf ich hinarbeite.

Wenn ein POST, der mehrere Ressourcen hinzufügt, erfolgreich ist, geben Sie ein 200 OK (ich habe ein 201 in Betracht gezogen, aber der Benutzer landet letztendlich nicht auf einer erstellten Ressource) zusammen mit einer Seite zurück, auf der alle hinzugefügten Ressourcen entweder beim Lesen angezeigt werden -nur oder bearbeitbare Mode. Beispielsweise kann ein Benutzer mehrere Bilder auswählen und in eine Galerie POSTEN, indem er ein Formular verwendet, das nur eine einzige Dateieingabe enthält. Wenn die POST-Anforderung vollständig erfolgreich ist, wird dem Benutzer für jede erstellte Bildressourcendarstellung eine Reihe von Formularen angezeigt, mit denen er weitere Details zu jeder (Name, Beschreibung usw.) angeben kann.

Für den Fall, dass eine oder mehrere Ressourcen nicht erstellt werden können, bricht der POST-Handler die gesamte Verarbeitung ab und hängt jede einzelne Fehlermeldung an ein Array an. Anschließend wird ein 419-Konflikt zurückgegeben und der Benutzer wird zu einer 419-Konfliktfehlerseite weitergeleitet, auf der der Inhalt des Fehlerarrays sowie ein Weg zurück zu dem übermittelten Formular angezeigt wird.

Eric Fuller
quelle
-2

Sie möchten die HTTP-Header nicht für 100 Bestellpositionen senden. Sie möchten auch nicht mehr Anfragen als nötig generieren.

Senden Sie die gesamte Bestellung in einem JSON-Objekt an den Server an: server / order oder server / order / new. Geben Sie etwas zurück, das auf Folgendes zeigt: server / order / order_id

Erwägen Sie auch die Verwendung von CREATE PUT anstelle von POST

Heiter
quelle
Ich nehme an, er erwähnt die HTTP-POST-Methode. Es gibt keine CREATE HTTP-Methode.
Milan Novota
Gibt es nicht Oh warte, das gab es nicht. Es gab stattdessen PUT.
Fröhlich
22
Warum um alles in der Welt würden Sie PUT zum Erstellen von Inhalten verwenden? Genau dafür ist die HTTP-POST-Methode gedacht.
Thecoshman
8
Sie verwenden PUT, um Ressourcen zu erstellen, wenn der Client den URI der Ressource angeben soll, wie in webdav. Ich bin mit der Verwendung von PUT durch das Poster nicht einverstanden, aber es hat einen Platz beim Erstellen von Ressourcen, obwohl dieser Platz möglicherweise in seinem Umfang begrenzt ist.
user602525
2
Hinweis: Das POSTEN einer Entität sollte dazu führen, dass die Entität der in der Anforderung adressierten Ressource untergeordnet wird und nicht idempotent ist. PUT ersetzt die Entität an der Adresse und ist idempotent. Die Idempotenz (Wort?) Ist eine wichtige Erwartung für die Verbraucher.
Luke Puplett