Zastanawiam się, jak zaimplementowałbyś następujący przypadek użycia w REST. Czy w ogóle można się obejść bez kompromisu w modelu konceptualnym?
Odczytuj lub aktualizuj wiele zasobów w ramach jednej transakcji. Na przykład przelej 100 USD z konta bankowego Roberta na konto Jana.
O ile wiem, jedynym sposobem na to jest oszukiwanie. Możesz POST do zasobu powiązanego z Janem lub Bobem i przeprowadzić całą operację przy użyciu pojedynczej transakcji. Jeśli o mnie chodzi, zrywa to architekturę REST, ponieważ zasadniczo tunelujesz wywołanie RPC przez POST, zamiast naprawdę działać na poszczególnych zasobach.
Jest kilka ważnych przypadków, na które nie ma odpowiedzi na to pytanie, co moim zdaniem jest złe, ponieważ ma wysoką pozycję w Google pod względem wyszukiwanych haseł :-)
W szczególności fajne byłoby, gdyby: Jeśli POST dwa razy (ponieważ część pamięci podręcznej czknęła w pośrednim), nie powinieneś przenosić kwoty dwukrotnie.
Aby się do tego dostać, należy utworzyć transakcję jako obiekt. Może zawierać wszystkie znane już dane i ustawić transakcję w stanie oczekującym.
Gdy już masz tę transakcję, możesz ją zatwierdzić, na przykład:
Zauważ, że wielokrotne puttowanie nie ma w tym momencie znaczenia; nawet GET na txn zwróciłby bieżący stan. W szczególności druga PUT wykryłaby, że pierwsza była już w odpowiednim stanie i po prostu zwróciłaby ją - lub, jeśli spróbujesz wprowadzić ją w stan „wycofania” po tym, jak jest już w stanie „zatwierdzone”, otrzymasz błąd, a rzeczywista zatwierdzona transakcja z powrotem.
Tak długo, jak rozmawiasz z pojedynczą bazą danych lub bazą danych ze zintegrowanym monitorem transakcji, mechanizm ten będzie działał dobrze. Możesz dodatkowo wprowadzić limity czasu dla transakcji, które możesz nawet wyrazić za pomocą nagłówków Expires, jeśli chcesz.
źródło
W kategoriach REST zasoby to rzeczowniki, na które można działać za pomocą czasowników CRUD (tworzenie / odczytywanie / aktualizowanie / usuwanie). Ponieważ nie ma czasownika „transfer pieniędzy”, musimy zdefiniować zasób „transakcji”, na który można działać za pomocą CRUD. Oto przykład w HTTP + POX. Pierwszym krokiem jest TWORZENIE (metoda HTTP POST) nowej pustej transakcji:
Zwraca to identyfikator transakcji, np. „1234” i zgodnie z adresem URL „/ transaction / 1234”. Należy pamiętać, że wielokrotne uruchomienie tego testu POST nie utworzy tej samej transakcji z wieloma identyfikatorami, a także pozwoli uniknąć wprowadzenia stanu „oczekujący”. Ponadto POST nie zawsze może być idempotentny (wymaganie REST), więc ogólnie dobrą praktyką jest minimalizowanie danych w POST.
Możesz pozostawić generowanie identyfikatora transakcji klientowi. W takim przypadku należy POST / transaction / 1234 utworzyć transakcję „1234”, a serwer zwróciłby błąd, gdyby już istniała. W odpowiedzi błędu serwer może zwrócić aktualnie nieużywany identyfikator z odpowiednim adresem URL. Nie jest dobrym pomysłem wysyłanie zapytań do serwera o nowy identyfikator za pomocą metody GET, ponieważ GET nigdy nie powinien zmieniać stanu serwera, a utworzenie / zarezerwowanie nowego identyfikatora zmieniłoby stan serwera.
Następnie AKTUALIZUJEMY (metoda PUT HTTP) transakcję ze wszystkimi danymi, pośrednio ją zatwierdzając:
Jeśli transakcja o identyfikatorze „1234” została wcześniej PUT, serwer wyświetli odpowiedź o błędzie, w przeciwnym razie odpowiedź OK i adres URL umożliwiający wyświetlenie zakończonej transakcji.
Uwaga: w / account / john, „john” powinno naprawdę być unikalnym numerem konta Jana.
źródło
Świetne pytanie, REST jest głównie wyjaśniony na przykładach podobnych do bazy danych, gdzie coś jest przechowywane, aktualizowane, odzyskiwane, usuwane. Takich przykładów jak ten jest kilka, gdzie serwer ma w jakiś sposób przetwarzać dane. Nie sądzę, żeby Roy Fielding zawarł to w swojej pracy, która w końcu była oparta na http.
Ale on mówi o „reprezentacyjnym transferze stanu” jako o maszynie stanów, z łączami przechodzącymi do następnego stanu. W ten sposób dokumenty (reprezentacje) śledzą stan klienta, zamiast tego, że serwer musi to robić. W ten sposób nie ma stanu klienta, a jedynie określ, na którym linku się znajdujesz.
Myślałem o tym i wydaje mi się rozsądne, że aby zmusić serwer do przetworzenia czegoś za Ciebie, po przesłaniu serwera automatycznie utworzy powiązane zasoby i poda linki do nich (w rzeczywistości nie nie trzeba ich tworzyć automatycznie: może po prostu wskazać linki, a tworzy je tylko wtedy, gdy je podążasz - leniwe tworzenie). A także aby dać ci linki do tworzenia nowych powiązanych zasobów - powiązany zasób ma ten sam identyfikator URI, ale jest dłuższy (dodaje sufiks). Na przykład:
/transaction
Glitch spowoduje utworzenie wielu takich zasobów, każdy z innym URI./transaction/1234/proposed
,/transaction/1234/committed
Jest to podobne do działania stron internetowych, gdzie końcowa strona internetowa mówi „Czy na pewno chcesz to zrobić?” Ta ostatnia strona internetowa jest sama w sobie reprezentacją stanu transakcji, która zawiera łącze do następnego stanu. Nie tylko transakcje finansowe; także (np.) podgląd, a następnie zatwierdzenie na wikipedii. Wydaje mi się, że różnica w REST polega na tym, że każdy etap w sekwencji stanów ma jawną nazwę (jego identyfikator URI).
W rzeczywistych transakcjach / sprzedaży często istnieją różne dokumenty fizyczne dla różnych etapów transakcji (propozycja, zamówienie zakupu, pokwitowanie itp.). Jeszcze bardziej za zakup domu, z rozliczeniem itp.
OTOH To dla mnie jak zabawa semantyką; Nie podoba mi się nominalizacja konwertowania czasowników na rzeczowniki, aby była REST-owa, „ponieważ używa rzeczowników (URI) zamiast czasowników (wywołania RPC)”. tzn. rzeczownik „zatwierdzony zasób transakcji” zamiast czasownika „zatwierdzić tę transakcję”. Myślę, że jedną z zalet nominalizacji jest to, że możesz odwoływać się do zasobu po nazwie, zamiast określać go w inny sposób (np. Utrzymując stan sesji, aby wiedzieć, czym jest ta transakcja ...)
Ale ważne pytanie brzmi: jakie są zalety tego podejścia? tj. w jaki sposób ten styl REST jest lepszy niż styl RPC? Czy technika, która doskonale sprawdza się w przypadku stron internetowych, jest również pomocna w przetwarzaniu informacji, poza przechowywaniem / pobieraniem / aktualizowaniem / usuwaniem? Myślę, że kluczową zaletą REST jest skalowalność; jednym z aspektów nie jest konieczność jawnego utrzymywania stanu klienta (ale uczynienie go niejawnym w identyfikatorze URI zasobu, a następne stany jako łącza w jego reprezentacji). W tym sensie to pomaga. Może to pomaga również w układaniu warstw / rurociągach? OTOH tylko jeden użytkownik będzie patrzył na swoją konkretną transakcję, więc nie ma żadnej korzyści z buforowania jej, aby inni mogli ją odczytać, wielka wygrana dla http.
źródło
Jeśli cofniesz się przed podsumowaniem dyskusji tutaj, jest całkiem jasne, że REST nie jest odpowiedni dla wielu interfejsów API, szczególnie gdy interakcja klient-serwer jest z natury stanowa, tak jak ma to miejsce w przypadku nietrywialnych transakcji. Po co przeskakiwać przez wszystkie sugerowane obręcze, zarówno dla klienta, jak i serwera, aby pedantycznie przestrzegać jakiejś zasady, która nie pasuje do problemu? Lepszą zasadą jest zapewnienie klientowi najłatwiejszego, najbardziej naturalnego i produktywnego sposobu komponowania z aplikacją.
Podsumowując, jeśli naprawdę wykonujesz wiele transakcji (typów, a nie instancji) w swojej aplikacji, naprawdę nie powinieneś tworzyć interfejsu API RESTful.
źródło
Od 10 lat oddalam się od tego tematu. Wracając, nie mogę uwierzyć w religię podszywającą się pod naukę, w którą wkraczasz, gdy Google Rest + jest wiarygodne. Zamieszanie jest mityczne.
Podzieliłbym to szerokie pytanie na trzy:
Jest to ważne, ponieważ pozwala wszystkim kolejnym żądaniom być w pełni idempotentne, w tym sensie, że jeśli zostaną powtórzone n razy, zwrócą ten sam wynik i nic więcej się nie stanie. Serwer przechowuje wszystkie odpowiedzi względem identyfikatora akcji i jeśli zobaczy to samo żądanie, odtwarza tę samą odpowiedź. Pełniejsze omówienie wzoru znajduje się w tym dokumencie Google . Dokument sugeruje implementację, która, jak sądzę (!), Jest zgodna z zasadami REST. Eksperci na pewno powiedzą mi, jak to narusza innych. Ten wzorzec może być przydatny w przypadku każdego niebezpiecznego połączenia z usługą internetową, niezależnie od tego, czy są zaangażowane transakcje podrzędne.
Twoje wymagania są fundamentalne. Nie pozwól ludziom wmawiać, że Twoje rozwiązanie nie jest koszerne. Oceń ich architektury pod kątem tego, jak dobrze i jak prosto rozwiązują Twój problem.
źródło
Będziesz musiał utworzyć własny typ zarządzania wysyłkami typu „identyfikator transakcji”. Więc to byłyby 4 wywołania:
Będziesz musiał obsłużyć przechowywanie akcji w bazie danych (jeśli obciążenie jest zrównoważone) lub w pamięci lub w tym podobnym, a następnie obsłużyć zatwierdzenie, wycofanie, limit czasu.
Niezbyt spokojny dzień w parku.
źródło
Myślę, że w tym przypadku całkowicie dopuszczalne jest w tej sytuacji złamanie czystej teorii REST. W każdym razie nie sądzę, aby w REST było coś, co mówi, że nie można dotykać zależnych obiektów w przypadkach biznesowych, które tego wymagają.
Naprawdę uważam, że nie warto robić dodatkowych kółek, przez które przeskoczysz, aby stworzyć niestandardowego menedżera transakcji, kiedy możesz po prostu wykorzystać bazę danych do tego.
źródło
Przede wszystkim przekazanie pieniędzy to nic, czego nie możesz zrobić w jednym wezwaniu do pomocy. Akcja, którą chcesz zrobić, to wysyłanie pieniędzy. Więc dodajesz zasób przekazu pieniężnego na konto nadawcy.
Gotowe. Nie musisz wiedzieć, że jest to transakcja, która musi być atomowa itp. Po prostu przelewasz pieniądze aka. wysłać pieniądze z punktu A do B.
Ale w rzadkich przypadkach tutaj ogólne rozwiązanie:
Jeśli chcesz zrobić coś bardzo złożonego, obejmującego wiele zasobów w określonym kontekście z wieloma ograniczeniami, które faktycznie przekraczają barierę „co / dlaczego” (wiedza biznesowa a wdrożeniowa), musisz przenieść stan. Ponieważ REST powinien być bezstanowy, jako klient musisz przenosić stan.
Jeśli przenosisz stan, musisz ukryć informacje przed klientem. Klient nie powinien znać wewnętrznych informacji potrzebnych tylko do wdrożenia, ale nie powinien posiadać informacji istotnych z punktu widzenia biznesu. Jeśli te informacje nie mają wartości biznesowej, należy zaszyfrować stan i użyć metafory, takiej jak token, przepustka lub coś innego.
W ten sposób można przekazać stan wewnętrzny, a szyfrowanie i podpisywanie systemu może być nadal bezpieczne i solidne. Znalezienie odpowiedniej abstrakcji dla klienta, dlaczego przekazuje informacje o stanie, zależy od projektu i architektury.
Prawdziwe rozwiązanie:
Pamiętaj, że REST mówi o HTTP, a HTTP zawiera koncepcję używania plików cookie. Te pliki cookie są często zapomniane, gdy ludzie mówią o REST API oraz przepływach pracy i interakcjach obejmujących wiele zasobów lub żądań.
Pamiętaj, co jest napisane w Wikipedii o plikach cookie HTTP:
Zasadniczo, jeśli chcesz przekazać stan, użyj pliku cookie. Został zaprojektowany z dokładnie tego samego powodu, jest to HTTP i dlatego jest zgodny z REST z założenia :).
Lepsze rozwiązanie:
Jeśli mówisz o kliencie wykonującym przepływ pracy obejmujący wiele żądań, zwykle mówisz o protokole. Każda forma protokołu zawiera zestaw warunków wstępnych dla każdego potencjalnego kroku, takich jak wykonanie kroku A, zanim będzie można wykonać B.
Jest to naturalne, ale ujawnienie protokołu klientom komplikuje wszystko. Aby tego uniknąć, pomyśl tylko, co robimy, gdy musimy wykonywać złożone interakcje i robić rzeczy w prawdziwym świecie ... Korzystamy z agenta.
Korzystając z metafory agenta, możesz zapewnić zasób, który może wykonać wszystkie niezbędne kroki za Ciebie i zapisać na swojej liście faktyczny przydział / instrukcje, na podstawie których działa (abyśmy mogli użyć POST na agencie lub „agencji”).
Złożony przykład:
Kupno domu:
Musisz udowodnić swoją wiarygodność (np. Dostarczając wpisy z akt policyjnych), musisz zapewnić szczegóły finansowe, musisz kupić rzeczywisty dom za pośrednictwem prawnika i zaufanej osoby trzeciej przechowującej fundusze, zweryfikować, czy dom należy teraz do Ciebie i dodaj informacje o zakupach do swoich ewidencji podatkowych itp. (na przykład niektóre kroki mogą być błędne lub cokolwiek innego).
Wykonanie tych czynności może zająć kilka dni, niektóre można wykonać równolegle itp.
Aby to zrobić, wystarczy dać agentowi zadanie kupna domu, takie jak:
Gotowe. Agencja odsyła Ci referencję, której możesz użyć do sprawdzenia i śledzenia statusu tej pracy, a reszta jest wykonywana automatycznie przez agentów agencji.
Pomyśl na przykład o narzędziu do śledzenia błędów. Zasadniczo zgłaszasz błąd i możesz użyć identyfikatora błędu, aby sprawdzić, co się dzieje. Możesz nawet skorzystać z usługi, aby nasłuchiwać zmian w tym zasobie. Misja wykonana.
źródło
Nie możesz używać transakcji po stronie serwera w REST.
Jeden z ograniczeń REST:
Jedynym sposobem RESTful jest utworzenie dziennika powtórzeń transakcji i wprowadzenie go do stanu klienta. Wraz z żądaniami klient wysyła dziennik powtórzeń, a serwer ponawia transakcję i
Ale może prostsze jest użycie technologii opartej na sesji serwera, która obsługuje transakcje po stronie serwera.
źródło
Uważam, że miałoby to miejsce w przypadku użycia unikalnego identyfikatora wygenerowanego na kliencie, aby upewnić się, że czkawka połączenia nie oznacza dwulicowości zapisanej przez API.
Myślę, że użycie pola GUID wygenerowanego przez klienta wraz z obiektem transferu i upewnienie się, że ten sam identyfikator GUID nie został ponownie wstawiony, byłoby prostszym rozwiązaniem w przypadku przelewu bankowego.
Nie znasz bardziej złożonych scenariuszy, takich jak rezerwacja wielu biletów lotniczych lub mikroarchitektury.
Znalazłem artykuł na ten temat, dotyczący doświadczeń związanych z niepodzielnością transakcji w usługach RESTful .
źródło
W prostym przypadku (bez zasobów rozproszonych) transakcję można by traktować jako zasób, w którym akt jej tworzenia osiąga cel końcowy.
Tak więc, aby przenieść między
<url-base>/account/a
i<url-base>/account/b
, możesz wysłać następujące wiadomości do<url-base>/transfer
.Spowoduje to utworzenie nowego zasobu transferu i zwrócenie nowego adresu URL transferu - na przykład
<url-base>/transfer/256
.W momencie pomyślnego zaksięgowania na serwerze przeprowadzana jest więc „prawdziwa” transakcja, a kwota pobierana z jednego konta i dodawana do drugiego.
Nie obejmuje to jednak transakcji rozproszonych (jeśli, powiedzmy, „a” jest przetrzymywane w jednym banku za jedną usługą, a „b” jest przechowywane w innym banku za inną usługą) - inne niż stwierdzenie „spróbuj ująć wszystko operacje w sposób niewymagający transakcji rozproszonych ”.
źródło
Myślę, że możesz dołączyć TAN do adresu URL / zasobu:
Tylko pomysł.
źródło