REST-Endpunkt, um vor dem POST eine Vorschau anzuzeigen

17

Ich entwerfe eine neue Webanwendung, die auf einem REST-Backend und einem HTML + JS-Frontend basiert.

Es gibt eine POST- Methode, um eine Entität zu ändern (rufen wir Config auf), die im Status vieler Elemente der Anwendung mehrere Nebenwirkungen hat. Nehmen wir an, der POST wird folgendermaßen durchgeführt:

POST /api/config BODY {config: ....}

Aus diesem Grund möchte ich eine Vorschau anzeigen, bevor diese Änderungen vorgenommen werden, damit der Endbenutzer feststellen kann, was sich ändern wird.

Zuerst habe ich darüber nachgedacht, einen GET- Endpunkt für die Vorschau zu erstellen und den Hauptteil des neuen Status der Entität zu senden. Diesen Weg:

GET /api/preview/items BODY {config: ....}

Möglicherweise wird der neue Status für die Elemente mit der neuen Konfiguration angezeigt.

GET /api/preview/sales BODY {config: ....}

Könnte den neuen Status für den Verkauf mit der neuen Konfiguration anzeigen.

Es scheint eine gute Idee zu sein, das Verb GET zu verwenden, da ich den Status der Anwendung nicht ändere. Von der Verwendung eines Anforderungshauptteils mit GET- Anforderungen wird jedoch anscheinend abgeraten .

Gibt es eine gute Praxis dazu? Eine andere Möglichkeit besteht darin, die Konfiguration als Entwurf mit einer Methode zu speichern und die Ergebnisse mit anderen anzuzeigen. Es ist jedoch ein zusätzlicher Schritt erforderlich und die Entwürfe müssen auf dem Server verwaltet werden:

POST /api/preview/config BODY {config: ....}

GET /api/preview/items?idPreviewConfig=1
Xtreme Biker stellt Monica wieder her
quelle
Was genau könnte diese Konfiguration sein und wie wirkt es sich auf die itemsoder aus sales? Beeinflusst es die Darstellung der zurückgegebenen Entität?
Andy
Nehmen wir an, dass sowohl Artikel als auch Verkäufe von den Änderungen betroffen sind, die Sie in der Konfiguration vornehmen.
Xtreme Biker setzt Monica
Aber was bedeuten die Änderungen? Ändert es die Menge der zurückgegebenen Entitäten? Ändert es die zurückgegebene Struktur?
Andy
Tatsächlich ändert es die Werte für itemsund sales(nicht die Struktur), abhängig von der Konfiguration, die Sie POST.
Xtreme Biker setzt Monica
Und wie groß ist die Konfiguration genau? Kann in bis zu mehreren hundert Kilobyte oder sogar mehr wachsen?
Andy

Antworten:

27

Dies ist zu domänenspezifisch, um eine native Unterstützung in HTTP zu haben.

Sie können stattdessen eine der folgenden Aktionen ausführen:

  1. Habe ein POST /api/config/preview. Auf der Serverseite weiß die Anwendung, dass die tatsächliche Konfiguration nicht geändert werden sollte, sondern dass die tatsächliche Konfiguration mit der von Ihnen veröffentlichten Konfiguration kombiniert werden sollte, und gibt das Ergebnis zurück, das angibt, was geändert wurde.

    Wenn der Benutzer später mit dem Ergebnis zufrieden ist, führt er eine POST /api/configPrüfung mit derselben Nutzlast wie in der vorherigen Anforderung durch. Dadurch wird die Konfiguration effektiv überschrieben.

    Der Vorteil dieses Ansatzes besteht darin, dass Sie keine wesentlichen Änderungen an der aktuellen API vornehmen. Kunden, die die Vorschaufunktion nicht benötigen, können die Einträge weiterhin wie bisher aktualisieren.

    Der Nachteil ist, dass bei einem großen Textkörper dieser zweimal an den Server gesendet werden muss. In diesem Fall können Sie den nächsten Ansatz verwenden.

  2. Haben Sie eine, POST /api/config/preparedie sich merkt, was in einem temporären Datensatz gesendet wurde, und zwei Dinge zurückgibt: die ID des temporären Datensatzes (zum Beispiel 12345) und die Vorschau der Änderungen.

    Wenn der Benutzer mit dem Ergebnis zufrieden ist, führt er einen aus POST /api/config/commit/12345, um die Änderungen endgültig zu speichern. Andernfalls wird der temporäre Datensatz möglicherweise einige Zeit aufbewahrt und dann von einem Cron-Job verworfen.

    Der Vorteil ist, dass auch hier das Original POST /api/configerhalten bleibt und die Clients, die keine Vorschau benötigen, nicht beschädigt werden.

    Die Nachteile sind, dass (1) das Entfernen von temporären Datensätzen schwierig sein kann (aus welchem ​​Grund denken Sie, dass eine Stunde ausreicht? Was passiert, wenn zehn Minuten später nicht genügend Arbeitsspeicher zur Verfügung steht? Wie Clients mit HTTP 404 umgehen, wenn ein Commit von ausgeführt wird?) ein Datensatz, der abgelaufen ist?) und dass (2) das Einreichen eines Datensatzes in zwei Schritten komplizierter sein kann, als es sein muss.

  3. Verschieben Sie die Vorschaulogik auf der Clientseite.

Arseni Mourzenko
quelle
Wie wäre es, wenn Sie einen Header mit der Aufschrift "Behalte das nicht bei, zeige mir nur das Was-wäre-wenn" senden? Ich werde das in der Antwort ändern, wenn das für dich in Ordnung ist. @ArseniMourzenko
marstato
1
@marstato: Ich persönlich mag HTTP-Header für diese Verwendung nicht besonders. Obwohl es für andere Menschen sinnvoll sein kann, geht es mir gut, wenn Sie meine Antwort bearbeiten. Beachten Sie, dass Sie auch Ihre eigene Antwort posten können, die es anderen ermöglichen würde, sie zu bewerten (und Ihnen Reputationspunkte einbringt).
Arseni Mourzenko
Ich denke, Option 1 passt besser zu meinem Fall. Sie POSTEN also die Vorschau-Konfiguration und haben die Änderungen im Ergebnis, anstatt Vorschau-Endpunkte für jede der definierten Entitäten definieren zu müssen. Scheint vernünftig. Das einzige, was Sie tun müssen, ist, dass Sie einen POST verwenden, um technisch gesehen keine Änderungen am Server vorzunehmen. Option 3 ist in meinem Fall nicht durchführbar.
Xtreme Biker setzt Monica
1
@PedroWerneck Kannst du das erweitern? Es scheint mir, dass Option 2 eine andere Entität definiert (eine Entwurfskonfiguration) und zustandslose Möglichkeiten zur Interaktion mit ihnen bietet.
Andrew sagt Reinstate Monica
1
@PedroWerneck Es ist statusbehaftet, genauso wie das Speichern einer Konfiguration auf dem Server statusbehaftet ist. Aus Ihrer Sicht ist die Anwendung also bereits in einem Status, und alle Optionen zum Hinzufügen dieser Funktion sind ebenfalls vorhanden.
jpmc26
10

Der Sinn der Verwendung bestimmter HTTP-Verben für verschiedene API-Aufrufe in REST besteht darin, die vorhandenen HTTP-Mechanismen und -Erwartungen zu nutzen.

In diesem Fall scheint die Verwendung eines GET gegen beides zu verstoßen.

A. Der Client muss einen Body mit einem GET enthalten? unerwartet

B. Der Server gibt eine unterschiedliche Antwort auf ein Get zurück, abhängig vom Body? Bricht Spec und Caching-Mechanik

Wenn Sie mit REST-Fragen zu kämpfen haben, ist es meine Regel, sich selbst zu fragen.

"Wie ist das besser, als nur POST für alles zu verwenden?"

Wenn es keinen unmittelbaren und offensichtlichen Vorteil gibt, entscheiden Sie sich für die Just Use POST Stupid (JUPS) -Strategie

Ewan
quelle
Hahaha guter Fang
Xtreme Biker setzt Monica
@Ewan ... unabhängig davon, ob dies ein pragmatischer Ansatz ist oder nicht ... Wenn Sie POST für alles verwenden, sollte beachtet werden, dass es nicht wirklich RESTful ist.
Allenph
1
Nun, es sei denn, POST ist die richtige Wahl für alle Ihre Methoden. Und es ist nicht so, dass Sie eine objektive Regel anwenden können, wir würden nur unsere subjektiven Interpretationen von etwas argumentieren, was nicht mehr als eine Richtlinie ist.
Ewan
6

Sie können eine Kopfzeile senden, die dem Server mitteilt, dass Sie "dies nicht beibehalten, sondern nur anzeigen, was das Ergebnis wäre, wenn Sie dies getan hätten". Z.B

POST /api/config HTTP/1.1
Host: api.mysite.com
Content-Type: application/json
Persistence-Options: simulate

{
   "config": {
      "key": "value"
   }
}

Auf die der Server antworten könnte:

HTTP/1.1 200 OK
Persistence-Options: simulated
Content-Type: application/json

-- preview --

Beachten Sie, dass Sie, wenn Sie eine auf Arbeitseinheiten basierende O / RM- und / oder Pro-Anfrage-Transaktion mit Ihrer Datenbank verwenden, diese Funktionalität auf einfache Weise für alle Ihre Endpunkte implementieren können, ohne an einem bestimmten Endpunkt arbeiten zu müssen: Wenn eine Anfrage mit dieser Option eingeht Machen Sie die Transaktion / Arbeitseinheit rückgängig, anstatt sie festzuschreiben.

marstato
quelle
@ PeterRader guter Punkt, entfernt dieX-
Marstato
Gern geschehen. Würden Sie sagen, dass eine in der Simulation befindliche Entität als "in der Simulation" dargestellt werden sollte?
Peter Rader
Nein; das ist der Punkt einer Simulation, nicht wahr? Der Header-Wert könnte auch sein, noneaber das würde - für meinen Geschmack - der Natur der POSTMethode zu sehr widersprechen .
Marstato
2

Ich würde vorschlagen, dies genauso zu behandeln, wie Sie Suchanfragen behandeln. Ich würde einen POST-Endpunkt einrichten, an /api/config/previewdem eine neue Vorschau erstellt wird. Dann würde ich einen PUT- oder PATCH-Endpunkt einrichten, api/configje nachdem, ob Sie die aktuelle Konfiguration bearbeiten oder einfach die gesamte Konfiguration ersetzen möchten (vermutlich würden Sie im ersten Fall die gerade erstellte Vorschau senden).

Allenph
quelle
0

Neben den anderen guten Antworten besteht eine weitere Möglichkeit darin, die Konfiguration wie erwähnt zu veröffentlichen und auch einen Rollback-Prozess zur Verfügung zu stellen. Ich denke, wie bei der Agile-Methode ist es besser, sich vor Änderungen nicht zu fürchten, wenn Sie detailliertere, wiederholbarere und getestete Verfahren verwenden. Auf diese Weise können Sie bei Bedarf ein Backup erstellen und das Risiko je nach Anwendung auf ein geringes oder gar kein Risiko reduzieren .

Wenn Sie jedoch Konfigurationsfehler haben, die sich auf das gesamte System auswirken, möchten Sie diese möglicherweise aktiver behandeln. Wenn dies der Fall ist, sollten Sie sich nicht einfach die Mühe machen, die Änderungen an diesem Punkt aus Server- oder Client-Sicht in der Vorschau anzuzeigen. Obwohl ich sehen kann, wie teuer die Entwicklung dieser Vorschau-Funktion sein könnte, müssen bei den Anwendungsfällen unterschiedliche Schritte befolgt und getestet werden.

Pysis
quelle
0

RFC6648 veraltet neue X-Konstrukte, daher muss ich gegen die Idee stimmen, ein neues Header-Feld zu senden. REST ist ein Architekturstil, über den wir reden, ist RESTful - aber lassen Sie uns das für diesen Moment ignorieren.

Da REST repräsentativ ist (und eine Simulation keine Repräsentation in der Realität hat) und zustandsbehaftet (und eine Simulation erst dann ein Zustand ist, wenn sie festgeschrieben wurde), müssen wir einen neuen Bereich haben, wie einen Simulationsbereich. Aber wir müssen es Emulation statt Simulation nennen, weil Simulation den Prozess der Simulation beinhaltet, aber zustandsbehaftet bedeutet, dass wir einen stehenden Zustand haben, eine ideale Lösung einer Simulation: eine Emulation. Also müssen wir es Emulation in der URL nennen. Dies könnte auch eine gute Lösung sein:

GET  /api/emulation - 200 OK {first:1, last:123}
POST /api/emulation/124 - 200 OK
GET  /api/emulation/124/config - 200 OK {config:{tax:8}}
PUT  /api/emulation/124/config {config:{tax:16}} - 200 OK {config:{tax:16}}
GET  /api/emulation/124/items - 200 OK [first:1, last: 3000]
GET  /api/emulation/124/items/1 - 200 OK {price:1.79, name:'Cup'}
--- show emulation ---
--- commit emulation ---
PUT /api/config {config:{tax:16}}
DELETE /api/emulation/124 - 200 OK

Es gibt einen anderen Ansatz ... Sie haben vielleicht bemerkt, dass viele Anfragen vom HTML / JavaScript-Client zu vielen Anfragen führen , was die Grenze von ungefähr 17 Anfragen zur gleichen Zeit erreicht (siehe diese Seite ). Sie können die Verwendung von REST austauschen und anstatt lahme Objektzustände bereitzustellen, können Sie umfangreiche benutzerspezifische Seitenzustände bereitstellen. Beispiel:

GET /user/123/config - 200 OK {user:'Tim', date:3298347239847, currentItem:123, 
                  roles:['Admin','Customer'], config:{tax:16}, unsavedChanges:true, ...}

Mit freundlichen Grüßen

Peter Rader
quelle