REST-złożone aplikacje

Walczę o zastosowanie zasad RESTful do nowej aplikacji internetowej, nad którą pracuję. W szczególności chodzi o to, że aby być spokojnym, każde żądanie HTTP powinno zawierać wystarczająco dużo informacji, aby jego odbiorca mógł je przetworzyć, aby było w pełnej harmonii z bezpaństwową naturą HTTP.

Aplikacja umożliwia użytkownikom wyszukiwanie leków. Wyszukiwanie akceptuje filtry jako dane wejściowe, na przykład zwrot odstawionych leków, obejmują bezpłatną terapię itp..itd. W sumie istnieje około 30 filtrów, które można zastosować.

DODATKOWO można wprowadzić dane pacjenta, w tym wiek pacjenta, płeć, aktualne leki itp.

Aby być spokojnym, czy wszystkie te informacje powinny być dołączone do każdej prośby? Wydaje się, że to powoduje ogromne obciążenie sieci. Ponadto, czy ograniczenia dotyczące długości URL, przynajmniej dla GET, nie sprawią, że będzie to niewykonalne?

Author: Alistair77, 2009-08-19

5 answers

"Filtr jako zasób" jest do tego idealnym taktem.

Możesz umieścić definicję filtra w zasobie filtra i może on zwrócić identyfikator filtra.

PUT jest idempotentny, więc nawet jeśli filtr już tam jest, Musisz tylko wykryć, że widziałeś filtr wcześniej, więc możesz zwrócić odpowiedni identyfikator dla filtra.

Następnie możesz dodać parametr filtra do innych żądań, a oni mogą pobrać filtr, aby użyć go do zapytań.

GET / leki?filter=1234&page=4&pagesize=20

Chciałbym uruchomić filtry raw przez jakiś proces kanoniczny, po prostu mieć znormalizowany zestaw, tak, że np filtr "firstname=Bob Lastname=Eubanks" jest identyczny z "LastName=Eubanks firstname=Bob". To tylko ja.

Jedynym problemem jest to, że w miarę upływu czasu może być konieczne zdezaktualizowanie niektórych filtrów. Możesz po prostu popełnić błąd w żądaniu, jeśli ktoś zgłosi żądanie z brakującym lub przestarzałym filtr.

Edytuj odpowiedź na pytanie...

Zacznijmy od podstaw.

Po prostu chcesz określić filtr do użycia w zapytaniach, ale te filtry są (potencjalnie) zaangażowane i skomplikowane. Gdyby to było proste / 1234, to nie byłoby problemu.

Skutecznie, zawsze trzeba wysłać filtr do zapytania. Pytanie brzmi, jak reprezentować ten filtr.

Podstawowym problemem takich rzeczy jak sesje w systemach REST jest to, że są zazwyczaj zarządzane "poza pasmem". Kiedy, powiedzmy, idziesz i tworzysz lek, umieszczasz lub publikujesz w zasobie leków i dostajesz odniesienie do tego leku.

W przypadku sesji (zazwyczaj) odzyskasz plik cookie lub inny token do reprezentowania tej sesji. Jeśli twój wkład do zasobów leków stworzył również Sesję, to w rzeczywistości twoja prośba stworzyła dwa zasoby: lek i sesję.

Niestety, gdy używasz czegoś takiego jak plik cookie, a ty potrzebujesz tego pliku cookie do swojego żądania, nazwa zasobu nie jest już prawdziwą reprezentacją zasobu. Teraz jest to nazwa zasobu (adres URL) i plik cookie.

Więc, jeśli zrobić dostać na zasobu o nazwie / leki / Szukaj, a plik cookie reprezentuje sesję, a ta sesja dzieje się mieć filtr w nim, można zobaczyć, jak w efekcie, że nazwa zasobu, / leki / szukaj, nie jest naprawdę przydatne w ogóle. Nie mam wszystkich informacji, które są mi potrzebne do skutecznego działania. korzystania, ze względu na efekt uboczny cookie i sesji oraz filtr w niej zawarty.

Mógłbyś może przepisać nazwę:/leki / Szukaj?session = ABC123, skutecznie osadzając plik cookie w nazwie zasobu.

Ale teraz biegniesz do typowego kontraktu sesji, zwłaszcza, że są one krótkotrwałe. Tak więc ten nazwany zasób jest mniej przydatny, długoterminowy, nie bezużyteczny, po prostu mniej przydatny. W tej chwili to zapytanie daje mi interesujące dane. Jutro? Pewnie nie. Przyniosę. paskudny błąd dotyczący zniknięcia sesji.

Innym problemem jest to, że sesje zazwyczaj nie są zarządzane jako zasób. Na przykład są one zwykle efektem ubocznym, a nie jawnie zarządzane przez GET/PUT / DELETE. Sesje są również "kupą śmieci" stanu aplikacji internetowej. W tym przypadku mamy tylko nadzieję, że sesja jest odpowiednio wypełniona tym, co jest potrzebne do tego żądania. Właściwie to nie wiemy. Znowu, to efekt uboczny.

Teraz obróćmy go trochę na głowę trochę. Let ' s use / leki / Szukaj?filtr = ABC123.

Oczywiście, od niechcenia, to wygląda identycznie. Właśnie zmieniliśmy nazwę z "session" na "filter". Ale, jak wspomniano, Filtry w tym przypadku są "zasobem pierwszej klasy". Muszą być tworzone, zarządzane itp. tak samo jak leki, pliki JPEG lub inne zasoby w Twoim systemie. To jest kluczowe rozróżnienie.

Oczywiście, można traktować "sesje" jako zasoby pierwszej klasy, tworząc je, umieszczając w nich rzeczy bezpośrednio itp. Ale widać, że, przynajmniej z punktu widzenia jasności, sesja "pierwszej klasy" nie jest naprawdę dobrą abstrakcją dla tego przypadku. Korzystanie z sesji, to jak pójście do pralni i przekazanie całej torebki lub teczki. "Tak, bilet jest gdzieś tam, wykop co chcesz, daj mi moje ubrania", zwłaszcza w porównaniu do czegoś wyraźnego jak filtr.

Widać więc, że przy 30 000 stopach nie ma dużej różnicy między filtrem a sesją. Ale kiedy przybliżasz, są zupełnie inne.

Z zasobem filtrów, możesz wybrać, aby stały się trwałe na zawsze i na zawsze. Możesz je wygasnąć, możesz robić, co chcesz. Sesje mają zazwyczaj wstępnie pomyślaną semantykę: krótkie życie, czas trwania połączenia itp. Filtry mogą mieć dowolną semantykę. Są całkowicie oddzielone od tego, co wiąże się z sesją.

Gdybym to robił, jak pracowałbym z filtrami?

Zakładam, że naprawdę nie dbaj o zawartość filtra. W szczególności wątpię, czy kiedykolwiek zapytałbym o "wszystkie filtry, które przeszukują po imieniu". W tym momencie wydaje się to nieciekawą informacją, więc nie będę projektował wokół niej.

Następnie chciałbym normalizować filtry, jak wspomniałem powyżej. Upewnij się, że równoważne filtry naprawdę są równoważne. Możesz to zrobić sortując wyrażenia, upewniając się, że nazwy pól są wielkimi literami lub cokolwiek innego.

Wtedy zapisałbym filtr jako XML lub JSON dokument, w zależności od tego, co jest bardziej wygodne/odpowiednie dla aplikacji. Dałbym każdemu filtrowi unikalny klucz (naturalnie), ale również przechowywałbym hash dla rzeczywistego dokumentu z filtrem.

Zrobiłbym to, aby móc szybko znaleźć, czy filtr jest już zapisany. Ponieważ normalizuję to, "Wiem", że XML (powiedzmy) dla logicznie równoważnych filtrów byłby identyczny. Tak więc, gdy ktoś idzie umieścić, lub wstawić nowy filtr, chciałbym zrobić sprawdzenie na hash, aby zobaczyć, czy został przechowywany wcześniej. Mogę wrócić więcej niż jeden (hasze mogą się kolidować, oczywiście), więc będę musiał sprawdzić rzeczywiste ładunki XML, aby zobaczyć, czy pasują.

Jeśli filtry pasują, zwracam odniesienie do istniejącego filtra. Jeśli nie, stworzyłem nowy i zwróciłem go.

Nie pozwoliłbym również na aktualizację/POST filtra. Ponieważ rozdaję odniesienia do tych filtrów, uczyniłbym je niezmiennymi, aby odniesienia mogły pozostać ważne. Gdybym chciał filtrować po "roli", powiedzmy, " get all expireate medicines filter", wtedy stworzyłbym zasób "named filter", który kojarzy nazwę z instancją filtra, tak aby rzeczywiste dane filtra mogły się zmienić, ale nazwa pozostaje taka sama.

Pamiętaj również, że podczas tworzenia jesteś w stanie rasowym( dwa żądania próbują zrobić ten sam filtr), więc musisz to wyjaśnić. Jeśli system ma dużą objętość filtra, może to być potencjalne wąskie gardło.

Mam nadzieję, że to wyjaśni ci problem.

 77
Author: Will Hartung,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-08-21 01:14:37
Czy aby być spokojnym, wszystkie te informacje powinny być dołączane do każdej prośby?
Nie. Jeśli wygląda na to, że twój serwer wysyła (lub odbiera) zbyt dużo informacji, jest szansa, że istnieje jeden lub więcej zasobów, których jeszcze nie zidentyfikowałeś.

Pierwszym i najważniejszym krokiem w projektowaniu systemu RESTful jest identyfikacja i nazwanie swoich zasobów. Jak byś to zrobił dla swojego systemu?

Z twojego opisu, oto jeden z możliwych zestawów zasoby:

  • User - użytkownik systemu (może lekarz lub pacjent (? W tym miejscu może być konieczne ujawnienie roli jako zasobu)
  • leki - rzeczy w butelce, ale może również reprezentować Rodzaj butelki (ilość i zawartość), lub może reprezentować konkretną butelkę - w zależności od tego, czy jesteś apteką, czy tylko help desk.
  • choroba - Stan, na który pacjent może chcieć weź Lek .
  • pacjent - osoba, która może wziąć Lek
  • zalecenie - Lek , który może być korzystny dla pacjenta w oparciu o chorobę , na którą cierpi.

Następnie można szukać relacji między zasobami;

  • użytkownik mA i należy do wielu ról
  • Lek mA i należy do wielu choroby
  • choroba ma wiele zaleceń .
  • pacjent mA i należy do wielu leków i chorób (biedak)
  • pacjent ma wiele zaleceń
  • zalecenie ma jednego pacjenta i ma jedną chorobę

Specyfika prawdopodobnie nie pasuje do twojego konkretnego problemu, ale pomysł jest prosty: stwórz sieć relacji między twoimi zasobami.

W tym momencie pomocne może być zastanowienie się nad strukturą URI, chociaż należy pamiętać, że REST API muszą być oparte na hipertekście :
# view all Recommendations for the patient
GET http://server.com/patients/{patient}/recommendations

# view all Recommendations for a Medication
GET http://servier.com/medications/{medication}/recommendations

# add a new Recommendation for a Patient
PUT http://server.com/patients/{patient}/recommendations

Ponieważ jest to REST, spędzasz większość swojego czasu definiując typy mediów używane do przesyłania reprezentacji zasobów między Klientem a serwerem.

Ujawniając więcej zasobów, możesz ograniczyć ilość danych, które muszą zostać przesłane podczas każde żądanie. Zauważ również, że w Uri nie ma parametrów zapytania. Serwer może być tak Stanowy, jak musi być, aby śledzić to wszystko, a każde żądanie może być w pełni niezależne.

 12
Author: Rich Apodaca,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-08-19 05:18:41

REST jest przeznaczony dla API, a nie (typowych) aplikacji. Nie próbuj klinować zasadniczo statecznej interakcji w bezpaństwowy model tylko dlatego, że czytasz o tym na Wikipedii.

Aby być spokojnym, czy wszystkie te informacje powinny być dołączone do każdej prośby? Wydaje się, że to powoduje ogromne obciążenie sieci. Ponadto, czy ograniczenia dotyczące długości URL, przynajmniej dla GET, nie sprawią, że będzie to niewykonalne?

Wielkość parametrów jest zwykle nieistotna w porównaniu do wielkości zasoby wysyłane przez serwer. Jeśli używasz tak dużych parametrów, że są one obciążeniem sieciowym, umieść je na serwerze raz, a następnie użyj ich jako zasobów.

Nie ma znaczących ograniczeń dotyczących długości URL-jeśli twój serwer ma taki limit, uaktualnij go. Prawdopodobnie ma lata i i tak jest pełen luk w zabezpieczeniach.

 10
Author: John Millikin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-08-18 20:54:08

Nie wszystko to nie musi być w każdym zapytaniu.

Każdy zasób (leki, historia pacjenta itp.) powinien mieć kanoniczny URI, który jednoznacznie go identyfikuje. W niektórych aplikacjach (np. opartych na Railach) będzie to coś w rodzaju " / patients/1234 "lub"/drugs / 5678", ale format URL jest nieistotny.

Klient, który wcześniej uzyskał URI dla zasobu (np. z wyszukiwania lub z łącza osadzonego w innym zasobie), może pobrać go za pomocą tego URI.

 5
Author: Licky Lindsay,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-08-18 20:59:36

Czy pracujesz nad RESTful API, które inne aplikacje będą używać do wyszukiwania danych? A może budujesz aplikację internetową ukierunkowaną na użytkownika końcowego, w której użytkownicy będą się logować i wykonywać te wyszukiwania?

Jeśli użytkownicy logują się, to jesteś już stateful, ponieważ będziesz mieć pewien rodzaj plików cookie sesji, aby utrzymać stan zalogowania. Chciałbym iść dalej i utworzyć obiekt sesji, który zawiera wszystkie filtry wyszukiwania. Jeżeli użytkownik nie ustawił żadnych filtrów, wtedy obiekt ten będzie pusty.

Oto świetny post na blogu o korzystaniu z GET vs POST. Wspomina limit długości URL ustawiony przez Internet Explorer 2,048 znaków, więc chcesz używać POST dla długich żądań.

Http://carsonified.com/blog/dev/the-definitive-guide-to-get-vs-post/

 0
Author: CoderDennis,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-08-18 21:01:40