REST-API-Design für Webseiten mit Assistenten

11

Ich habe eine Webseite im Assistentenformat. Die Übermittlungsschaltfläche an die API befindet sich im 4. Schritt des Assistenten. Ich möchte jedoch, dass die eingegebenen Daten in der Datenbank gespeichert werden, bevor Sie mit dem nächsten Schritt im Assistenten fortfahren. Ich möchte auch, dass die REST-API für die Seiten mit einer einzelnen Registerkarte funktioniert.

Daher habe ich die API so konzipiert, dass sie einen Abfrageparameter action = Draft oder Submit ausführt. Wenn es sich um eine Entwurfsaktion handelt, sind nur bestimmte Felder obligatorisch. Wenn die Aktion gesendet wird, sind alle Felder obligatorisch. Validierungen in der Service-Schicht der REST-API werden basierend auf dem Abfrageparameter durchgeführt. Es sieht so aus, als müsste ich die if / else-Klauseln in der Dokumentation explizit angeben. Ist dies eine akzeptable Form von RESTful Design? Was wäre das beste Design mit diesen Anforderungen?

TechCrunch
quelle
3
Warum müssen die Zwischendaten in der DB gespeichert werden?
Dan1701
2
@ Dan1701: So können Sie den Assistenten von einem anderen Computer aus fortsetzen. Beim Ausfüllen langer, komplexer Formulare kann es einige Tage dauern, bis alle erforderlichen Daten ausgefüllt sind, da der Benutzer möglicherweise nicht alle erforderlichen Daten zur Hand hat oder zusätzliche Dateien sammeln muss, um sie von verschiedenen Orten hochzuladen. Wenn Sie von einem anderen Gerät aus fortfahren können, können Sie den Assistenten laden, um ein Foto vom Mobiltelefon hochzuladen, und weiterhin eine lange Beschreibung / ein Argument mit einer echten Tastatur auf dem Desktop usw. eingeben.
Lie Ryan
In diesem Fall halte ich die Antwort von @ guillaume31 für sinnvoll.
Dan1701

Antworten:

7

Da Sie die Dinge zwischen den Assistentenschritten auf dem Server beibehalten möchten, ist es durchaus akzeptabel, jeden Schritt als separate Ressource zu betrachten. Etwas in diese Richtung:

POST /wizard/123/step1
POST /wizard/123/step2
POST /wizard/123/step3

Indem Sie Hypermedia-Links in die Antwort aufnehmen, können Sie den Client darüber informieren, was er nach diesem Schritt tun kann - gehen Sie für Zwischenschritte vorwärts oder rückwärts und für den letzten Schritt nichts. Ein Beispiel dafür sehen Sie in Abbildung 5 hier .

guillaume31
quelle
Ich verwende Angular für die Benutzeroberfläche. Ich bin mir also nicht sicher, wie hilfreich die Zustandsmaschine ist. Ich denke jedoch, dass schrittweise Ressourcen sinnvoller sind als das Verwalten einer anderen Tabelle. Außerdem sollte ich in der Lage sein, alles in einem einzigen Schritt einzureichen. Werde es heute auf diesem Design ausprobieren. Danke für die Hilfe.
TechCrunch
Bitte. Übrigens schließt sich der "Two Table" -Ansatz dabei nicht gegenseitig aus. Eine HTTP-Ressource pro Schritt bestimmt nicht Ihr Objektmodell auf dem Anwendungsserver, geschweige denn das Datenbankschema. Es ist nur eine Webdarstellung.
Guillaume31
1
@TechCrunch Grundsätzlich bedeutet Guillaume, dass das Objekt / die Tabelle, die das Formular darstellt, in Teile zerlegt werden kann, wobei bei jedem Schritt ein Teil des Modells gespeichert wird. Tatsächlich kann jeder "Schritt" ein Formular für einen Teil des gesamten Modells sein . Und wenn Sie diesen Ansatz wählen, macht es die Architektur tatsächlich unglaublich einfach. Jeder POST an den Server (erstellt oder) aktualisiert dasselbe Modell, und jedes GET lädt dasselbe Modell, und jeder Schritt ist ein Formular zum Ausfüllen von Feldern, die semantisch sinnvoll sind (zusammengehören). Und haben Sie einfach einen Booleschen Wert für in_progressoder draft.
Chris Cirefice
3

Ich musste vor einiger Zeit etwas Ähnliches tun, und das Folgende beschreibt, was wir am Ende haben.

Wir haben zwei Tabellen, Item und UnfinishedItem. Wenn der Benutzer die Daten mit dem Assistenten ausfüllt, werden die Daten in der Tabelle UnfinishedItem gespeichert. Bei jedem Assistentenschritt überprüft der Server die während dieses Schritts eingegebenen Daten. Wenn der Benutzer mit dem Assistenten fertig ist, rendert der Assistent ein verstecktes / schreibgeschütztes Formular auf einer Bestätigungsseite, auf der alle zu übermittelnden Daten angezeigt werden. Der Benutzer kann diese Seite überprüfen und zum entsprechenden Schritt zurückkehren, um Fehler zu beheben. Sobald der Benutzer mit seinen Eingaben zufrieden ist, klickt er auf Senden und der Assistent sendet alle Daten in den ausgeblendeten / schreibgeschützten Formularfeldern an den API-Server. Wenn der API-Server diese Anforderung verarbeitet, führt er alle Überprüfungen erneut aus, die er in jedem Schritt des Assistenten durchgeführt hat, und führt zusätzliche Überprüfungen durch, die nicht in die einzelnen Schritte passen (z. B. globale Überprüfungen, teure Überprüfungen).

Die Vorteile des Zwei-Tabellen-Ansatzes:

  • In der Datenbank können strengere Einschränkungen für die Item-Tabelle gelten als für die UnfinishedItem-Tabelle. Sie müssen keine optionalen Spalten haben, die nach Abschluss des Assistenten tatsächlich erforderlich sind.

  • Aggregierte Abfragen über die fertigen Elemente für die Berichterstellung sind einfacher, da Sie nicht daran denken müssen, die unfertigen Elemente auszuschließen. In unserem Fall mussten wir nie aggregierte Abfragen zwischen Item und UnfinishedItems durchführen, daher ist dies kein Problem.

Der Nachteil:

  • Es besteht die Gefahr, dass die Validierungslogik dupliziert wird. Das von uns verwendete Webframework, Django, macht dies etwas erträglicher, da wir die Modellvererbung mit ein wenig Metamagie verwendet haben, um die Einschränkungen zu ändern, die in Item und UnfinishedItem unterschiedlich sein müssen. Django generiert den größten Teil der Datenbank- und Formularvalidierung aus dem Modell, und wir müssen nur ein paar zusätzliche Validierungen darüber hacken.

Andere Möglichkeiten, die ich in Betracht gezogen habe und warum wir nicht mit ihnen gegangen sind:

  • Speichern der Daten in Cookies oder im lokalen Speicher: Benutzer können ihre Übermittlung nicht von einem anderen Gerät aus fortsetzen oder wenn sie ihren Browserverlauf löschen
  • Speichern Sie das UnfinishedItem als unstrukturierte Daten (z. B. JSON) in der Datenbank oder im sekundären Datenspeicher: Ich muss die Parsing-Logik definieren und kann die automatische Modell- / Formularvalidierung von Django nicht verwenden.
  • Führen Sie die Validierung pro Schritt auf der Clientseite durch: Ich muss die Validierungslogik zwischen Python / Django und JavaScript duplizieren.
Lie Ryan
quelle
1
+1 für den Hinweis auf Validierungen für Modelle vom Typ "Entwurf" und "fertige" Modelle; Daran habe ich nicht gedacht, und es ist ein wichtiger Punkt, der berücksichtigt werden sollte. Andernfalls hätten Sie wahrscheinlich eine Reihe von ifAussagen, die während Ihrer gesamten Validierung auf den Entwurfsstatus prüfen, was einfach nicht gut wäre. Obwohl einige sehr ausgefeilte Frameworks wie Ruby on Rails dieses Problem bei korrekter Implementierung erheblich vereinfachen könnten.
Chris Cirefice
1

Ich habe dies auf ähnliche Weise implementiert wie eine Mischung aus @ guillauma31 und @Lie Ryans Lösungen.

Hier sind die Schlüsselkonzepte:

  1. Es gibt einen 3-Schritt-Assistenten, der teilweise bis zum Abschluss beibehalten werden kann.
  2. Jeder Schritt hat seine eigene Ressource (zB .: /users/:id_user/profile/step_1, .../step_2etc.)
  3. Bei jedem Schritt können die Daten und der Abschlussstatus über GET-Anforderungen abgerufen und über PATCH-Anforderungen beibehalten werden.
  4. Jede Ressource hat ihre eigenen Validierungsregeln für die eingegebenen Daten.
  5. Jeder Schritt gibt einen Schlüssel zurück, der bei der Eingabe des nächsten Schritts verwendet werden muss, um die Reihenfolge zu gewährleisten. Sobald dieses Token verwendet oder ein neues generiert wurde, läuft es ab.
  6. Im letzten Schritt haben wir alle benötigten Daten in der Datenbank und ein Bestätigungsbildschirm wird angezeigt. Diese Bestätigung ruft eine andere Ressource auf, um die Daten als vollständig zu markieren (z. B.:) .../profile/confirm. Diese Ressource muss nicht alle Daten erneut empfangen. Es markiert nur die Daten als korrekt und vollständig.
  7. Es gibt eine geplante Routine, die diese unvollständigen Einträge löscht, die länger als ein paar Tage dauern.

Die Front-End-Leute müssen sich um die Token kümmern, damit der Hin- und Herfluss des Assistenten funktioniert.

Die API ist zustandslos und atomar.

Damit ein "Ein-Schritt-Assistent" mit diesem Setup funktioniert, müssen Sie einige Dinge ändern, z. B. den Token-Fluss entfernen oder eine Ressource erstellen, um Token basierend auf dem Assistententyp zurückzugeben, oder sogar eine neue Ressource erstellen, um nur diese bestimmte Single zu füllen Schritt-Assistent (wie PUT /users/:id_user/profile/).

Ricardo Souza
quelle