Projekt interfejsu API REST dla stron internetowych z kreatorami

11

Mam stronę internetową w formacie kreatora. Przycisk przesłania do interfejsu API będzie w 4 kroku kreatora. Jednak chcę, aby wprowadzone dane były przechowywane w bazie danych przed przejściem do następnego kroku w kreatorze. Chcę również, aby interfejs API REST działał dla stron posiadających jedną kartę.

Dlatego zaprojektowałem interfejs API, aby podejmował parametr zapytania action = szkic lub przesłanie. Jeśli działanie jest robocze, tylko niektóre pola są obowiązkowe. W przypadku przesłania akcji wszystkie pola są obowiązkowe. Sprawdzanie poprawności w warstwie usług interfejsu API REST zostanie wykonane na podstawie parametru zapytania. Wygląda na to, że muszę wyraźnie określić klauzule if / else w dokumentacji. Czy jest to akceptowalna forma projektu RESTful? Jaki byłby najlepszy projekt z tymi wymaganiami?

TechCrunch
źródło
3
Dlaczego dane tymczasowe muszą być przechowywane w bazie danych?
Dan1701
2
@ Dan1701: abyś mógł wznowić działanie kreatora z innego komputera. Podczas wypełniania długich, złożonych formularzy wypełnienie wszystkich wymaganych danych może potrwać kilka dni, ponieważ użytkownik może nie mieć pod ręką wszystkich niezbędnych danych lub może być konieczne zebranie dodatkowych plików w celu przesłania z różnych miejsc. Jeśli możesz wznowić pracę z innego urządzenia, możesz załadować kreatora, aby załadować zdjęcie z telefonu komórkowego i kontynuować pisanie długiego opisu / argumentu za pomocą prawdziwych klawiatur na komputerze itp.
Lie Ryan
W takim przypadku myślę, że odpowiedź @ guillaume31 ma sens.
Dan1701

Odpowiedzi:

7

Ponieważ chcesz zachować rzeczy na serwerze między krokami kreatora, wydaje się całkowicie akceptowalne uznanie każdego kroku za osobny zasób. Coś w tym stylu:

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

Uwzględniając w odpowiedzi linki hipermedialne, możesz poinformować klienta, co może zrobić po tym kroku - przejdź do przodu lub do tyłu, aby przejść do kroków pośrednich, a nic do ostatniego kroku. Przykład tego można zobaczyć na rycinie 5 tutaj .

guillaume31
źródło
Używam Angular do interfejsu użytkownika. Nie jestem więc pewien, jak bardzo pomocna jest maszyna stanowa. Ale myślę, że zasoby oparte na krokach wydają się mieć większe znaczenie niż zarządzanie inną tabelą. Powinienem też móc przesłać wszystko w jednym kroku. Dzisiaj wypróbuje ten projekt. Dzięki za pomoc.
TechCrunch
Nie ma za co. Nawiasem mówiąc, podejście „dwóch tabel” nie wyklucza się wzajemnie z tym. Posiadanie jednego zasobu HTTP na krok nie dyktuje modelu obiektowego na serwerze aplikacji, nie mówiąc już o schemacie bazy danych. To tylko reprezentacja sieci.
guillaume31
1
@TechCrunch Zasadniczo Guillaume oznacza, że ​​obiekt / tabela reprezentująca formularz można podzielić na części, w których część modelu jest zapisywana na każdym etapie. W rzeczywistości każdy krok może być formą dla części całego modelu . A jeśli zastosujesz to podejście, architektura stanie się niesamowicie prosta. Każdy test POST na serwerze spowoduje (utworzenie lub) aktualizację tego samego modelu, a każdy GET załaduje ten sam model, a każdy krok będzie formularzem do wypełnienia zestawów pól, które mają znaczenie semantyczne (należą do siebie). I po prostu mieć wartość logiczną na modelu dla in_progresslub draft.
Chris Cirefice,
3

Jakiś czas temu musiałem zrobić coś podobnego, a poniżej opisano, z czym skończymy.

Mamy dwie tabele, Item i UnfinishedItem. Gdy użytkownik wypełni dane za pomocą kreatora, dane są zapisywane w tabeli UnfinishedItem. Na każdym kroku kreatora serwer sprawdza poprawność danych wprowadzonych podczas tego kroku. Gdy użytkownik zakończy pracę z kreatorem, kreator wyświetla ukryty / dostępny tylko do odczytu formularz na stronie z potwierdzeniem, który pokazuje wszystkie dane, które należy przesłać. Użytkownik może przejrzeć tę stronę i wrócić do odpowiedniego kroku, aby naprawić błędy. Gdy użytkownik będzie zadowolony ze swoich wpisów, kliknie przycisk Prześlij, a następnie kreator prześle wszystkie dane w polach formularza ukrytego / tylko do odczytu do serwera API. Gdy serwer API przetwarza to żądanie, ponownie uruchamia wszystkie weryfikacje wykonane na każdym etapie kreatora i wykonuje dodatkowe weryfikacje, które nie pasują do poszczególnych kroków (np. Globalne weryfikacje, kosztowne weryfikacje).

Zalety dwóch tabel:

  • w bazie danych możesz mieć ściślejsze ograniczenia w tabeli przedmiotów niż w tabeli UnfinishedItem; nie musisz mieć opcjonalnych kolumn, które będą wymagane po zakończeniu pracy kreatora.

  • Zagregowane zapytania dotyczące gotowych elementów do raportowania są łatwiejsze, ponieważ nie trzeba pamiętać o wykluczeniu elementów niedokończonych. W naszym przypadku nigdy nie musieliśmy wykonywać zapytań zbiorczych między Przedmiotem a Niedokończonym Elementem, więc nie stanowi to problemu.

Wada:

  • Jest podatny na powielanie logiki sprawdzania poprawności. Wykorzystany przez nas framework internetowy, Django, czyni to nieco bardziej znośnym, ponieważ użyliśmy dziedziczenia modelu z odrobiną meta magii, aby zmienić ograniczenia, które musimy odróżnić w elementach i elementach niedokończonych. Django generuje większość baz danych i sprawdzanie poprawności formularzy na podstawie modelu, a my musimy jedynie zhakować kilka dodatkowych sprawdzeń poprawności.

Inne możliwości, które rozważałem i dlaczego nie poszliśmy z nimi:

  • zapisywanie danych w plikach cookie lub pamięci lokalnej: użytkownik nie może kontynuować przesyłania z innego urządzenia lub usunąć historię przeglądarki
  • przechowuj UnfinishedItem jako dane nieustrukturyzowane (np. JSON) w bazie danych lub w dodatkowym magazynie danych: Będę musiał zdefiniować logikę analizowania i nie będę mógł użyć automatycznej weryfikacji modelu / formularza Django.
  • wykonaj krokową weryfikację po stronie klienta: Będę musiał zduplikować logikę sprawdzania poprawności między Python / Django i JavaScript.
Lie Ryan
źródło
1
+1 za wskazanie walidacji modeli typu „szkicowego” i modeli „gotowych”; Nie myślałem o tym i jest to ważna kwestia, którą należy wziąć pod uwagę. W przeciwnym razie prawdopodobnie będziesz mieć mnóstwo ifwyciągów sprawdzających status wersji roboczej w trakcie sprawdzania poprawności, co byłoby po prostu niedobre. Chociaż niektóre bardzo wyrafinowane frameworki, takie jak Ruby on Rails, mogą znacznie uprościć ten problem, jeśli zostaną poprawnie zaimplementowane.
Chris Cirefice
1

Zaimplementowałem to w sposób podobny do mieszanki rozwiązań @ guillauma31 i @Lie Ryan.

Oto kluczowe pojęcia:

  1. Istnieje 3-krokowy kreator, który może być częściowo utrwalony aż do zakończenia.
  2. Każdy etap ma własny zasób IT (np .: /users/:id_user/profile/step_1, .../step_2itp)
  3. Na każdym etapie status danych i ukończenia można pobrać za pomocą żądań GET i utrwalić za pomocą żądań PATCH.
  4. Każdy zasób ma własne reguły sprawdzania poprawności wprowadzonych danych.
  5. Każdy krok zwraca klucz, którego należy użyć przy wprowadzaniu następnego kroku w celu zagwarantowania sekwencji. Po wykorzystaniu lub wygenerowaniu nowego, token wygasa.
  6. W ostatnim kroku mamy wszystkie potrzebne dane w bazie danych i wyświetla się ekran potwierdzenia. To potwierdzenie wywołuje inny zasób, aby oznaczyć dane jako kompletne (np .:) .../profile/confirm. Ten zasób nie musi ponownie odbierać wszystkich danych. Zaznacza tylko dane jako poprawne i kompletne.
  7. Istnieje zaplanowana procedura, która usuwa niekompletne wpisy, które mają więcej niż kilka dni.

Front-faceci muszą zająć się tokenami, aby uruchomić przepływ czarodzieja w tę iz powrotem.

Interfejs API jest bezstanowy i atomowy.

Aby „kreator działający w jednym kroku” działał z tą konfiguracją, musiałbyś zmienić niektóre rzeczy, takie jak usunięcie przepływu tokena lub utworzenie zasobu, który zwróci tokeny na podstawie typu kreatora, lub nawet utworzenie nowego zasobu tylko w celu wypełnienia tego konkretnego singla kreator kroków (jak PUT /users/:id_user/profile/).

Ricardo Souza
źródło