W jaki sposób wyszukiwania pasują do interfejsu RESTful?


137

Podczas projektowania interfejsu RESTful semantykę typów żądań uważa się za kluczową dla projektu.

  • GET - Wyświetl listę elementów do pobrania lub pobierania
  • PUT - zamień kolekcję lub element
  • POST - Utwórz kolekcję lub element
  • USUŃ - No cóż, usuń kolekcję lub element

Nie wydaje się to jednak obejmować pojęcia „wyszukiwania”.

Na przykład przy projektowaniu pakietu usług internetowych, które obsługują witrynę Job Search, możesz mieć następujące wymagania:

  • Uzyskaj indywidualną ofertę pracy
    • GET dodomain/Job/{id}/
  • Utwórz ogłoszenie o pracę
    • POST dodomain/Job/
  • Zaktualizuj ogłoszenie o pracę
    • PUT dodomain/Job/
  • Usuń ogłoszenie o pracę
    • USUŃ dodomain/Job/

„Zdobądź wszystkie prace” jest również proste:

  • GET dodomain/Jobs/

Jednak w jaki sposób „wyszukiwanie” pracy mieści się w tej strukturze?

Państwo mogłoby twierdzą, że jest to odmiana „lista kolekcji” i wdrożyć jako:

  • GET dodomain/Jobs/

Jednak wyszukiwania mogą być złożone i całkowicie możliwe jest utworzenie wyszukiwania, które generuje długi ciąg GET. Oznacza to, że odwołując się tutaj do pytania SO , występują problemy z ciągami GET dłuższymi niż około 2000 znaków.

Przykładem może być wyszukiwanie fasetowe - kontynuacja przykładu „praca”.

Mogę zezwolić na wyszukiwanie w aspektach - „Technologia”, „Stanowisko”, „Dyscyplina”, a także tekstowe słowa kluczowe, wiek pracy, lokalizacja i wynagrodzenie.

Dzięki płynnemu interfejsowi użytkownika oraz dużej liczbie technologii i tytułów pracy możliwe jest, że wyszukiwanie może obejmować wiele różnych aspektów.

Ulepsz ten przykład w CV, a nie w zadaniach, przynoszą jeszcze więcej aspektów, a możesz bardzo łatwo wyobrazić sobie wyszukiwanie z wybranymi setkami aspektów lub nawet tylko 40 aspektami, z których każdy ma długość 50 znaków (np. Tytuły pracy, nazwy uniwersytetów, Nazwy pracodawców).

W takiej sytuacji pożądane może być przeniesienie PUT lub POST, aby upewnić się, że dane wyszukiwania zostaną poprawnie wysłane. Na przykład:

  • POST dodomain/Jobs/

Ale semantycznie jest to instrukcja tworzenia kolekcji.

Państwo mogli również powiedzieć, musisz wyrazić to jak stworzenia wyszukiwania:

  • POST dodomain/Jobs/Search/

lub (zgodnie z sugestią Burngramma poniżej)

  • POST dodomain/JobSearch/

Semantycznie może się to wydawać sensowne, ale tak naprawdę nic nie tworzysz, tylko żądasz danych.

Więc semantycznie jest to GET , ale nie ma gwarancji , że GET będzie obsługiwał to, czego potrzebujesz.

Tak więc pytanie brzmi - starając się zachować jak najbardziej wierny projektowi RESTful, jednocześnie upewniając się, że trzymam się ograniczeń HTTP, jaki jest najbardziej odpowiedni projekt do wyszukiwania?


3
Często zamierzam używać GET domain/Jobs?keyword={keyword} . To działa dobrze dla mnie :) Mam nadzieję, że SEARCHczasownik stanie się standardem. programmers.stackexchange.com/questions/233158/…
Knerd

Tak, widzę, że w trywialnym przykładzie nie ma problemu. Ale w narzędziu, które budujemy, tak naprawdę nie jest to niewiarygodne, że skończylibyśmy złożonym wyszukiwaniem, którego wynikiem byłby ciąg GET dłuższy niż 2000 znaków. Co wtedy?
Rob Baillie

Właściwie to bardzo dobry punkt. Co powiesz na określenie technologii kompresji?
Knerd

2
GET z treścią jest dozwolony przez specyfikację HTTP, może być obsługiwany przez oprogramowanie pośrednie (czasem nie);) i nie jest preferowany jako praktyka. To pojawia się na Stackexchange okresowo. stackoverflow.com/questions/978061/http-get-with-request-body
Rob

2
Skończyło się na tym, że POST JobSearch utworzyło rzeczywistą jednostkę wyszukiwania i zwróciło JobSearchId. Następnie GET jobs? JobSearch = jobSearchId zwraca rzeczywistą kolekcję zadań.
Cerad

Odpowiedzi:


93

Nie należy zapominać, że żądania GET mają przewagę nad innymi rozwiązaniami:

1) Żądania GET można kopiować z paska adresu URL, są one przetwarzane przez wyszukiwarki, są „przyjazne”. Gdzie „przyjazny” oznacza, że ​​zwykle żądanie GET nie powinno modyfikować niczego w Twojej aplikacji (idempotent) . Jest to standardowy przypadek wyszukiwania.

2) Wszystkie te koncepcje są bardzo ważne nie tylko z punktu widzenia użytkownika i wyszukiwarki, ale z architektonicznego punktu widzenia projektowania interfejsu API .

3) Jeśli stworzysz obejście za pomocą POST / PUT , będziesz mieć problemy, o których teraz nie myślisz. Na przykład w przypadku przeglądarki przycisk nawiguj wstecz / odśwież stronę / historię. Można to oczywiście rozwiązać, ale to będzie kolejne obejście, potem kolejne i kolejne ...

Biorąc to wszystko pod uwagę, moja rada byłaby następująca:

a) Powinieneś być w stanie zmieścić się w swoim GET przy użyciu sprytnej struktury parametrów . W skrajnym przypadku możesz nawet skorzystać z taktyki, takiej jak wyszukiwarka Google, w której ustawiłem wiele parametrów, ale jest to bardzo krótki adres URL.

b) Utwórz inny podmiot w swojej aplikacji, taki jak JobSearch . Zakładając, że masz tyle opcji, prawdopodobne jest, że będziesz musiał również przechowywać te wyszukiwania i zarządzać nimi, więc po prostu wyczyść aplikację. Możesz pracować z obiektami JobSearch jako całością, co oznacza, że możesz je przetestować / używać łatwiej .


Osobiście starałbym się walczyć wszystkimi pazurami, aby to zrobić za pomocą a), a gdy cała nadzieja została utracona, czołgałam się ze łzami w oczach do opcji b) .


4
Dla wyjaśnienia pytanie to dotyczy projektowania usług internetowych, a nie projektowania witryn internetowych. Więc podczas gdy zachowanie przeglądarka ma znaczenie w szerszym zakresie interpretacji pytaniem jest, w szczególności przypadek opisany jest to bez znaczenia. (choć interesujący punkt).
Rob Baillie

@RobBaillie Ye przeglądarka była tylko przykładem użycia. Chciałem wyrazić fakt, że twoje wyszukiwanie jako całość jest reprezentowane przez ciąg adresu URL. Który ma duży komfort użytkowania i inne punkty w dalszej części odpowiedzi.
p1100i

W punkcie B, jest to prosta odmiana moim odniesieniem do POST do domain/Jobs/Search/, być może ze domain/JobsSearch/zamiast, albo miałeś na myśli coś innego? Możesz wyjaśnić?
Rob Baillie

7
Dlaczego mam wrażenie, że REST jest często częścią problemu, a nie częścią rozwiązania?
JensG

1
„Żądanie GET nie powinno modyfikować niczego w Twojej aplikacji (idempotent)”, podczas gdy GET jest idempotentny, odpowiednie słowo jest tutaj „ bezpieczne ”. Idempotent oznacza, że ​​dwukrotne wykonanie GET na zasobie jest takie samo, jak jednorazowe wykonanie GET na tym zasobie. Na przykład PUT jest idempotentny, ale nie jest bezpieczny.
Jasmijn

12

TL; DR: GET do filtrowania, POST do wyszukiwania

Dokonuję rozróżnienia między filtrowaniem wyników z listy kolekcji a złożonym wyszukiwaniem. Test lakmusowy, którego używam, jest w zasadzie, jeśli potrzebuję więcej niż filtrowania (dodatniego, ujemnego lub zakresu), uważam to za bardziej złożone wyszukiwanie wymagające POST.

Jest to zwykle wzmacniane, gdy myśli się o tym, co zostanie zwrócone. Zwykle używam GET tylko wtedy, gdy zasób ma przeważnie pełny cykl życia (PUT, DELETE, GET, collection GET) . Zazwyczaj w kolekcji GET zwracam listę identyfikatorów URI, które są zasobami REST, które tworzą tę kolekcję. W złożonym zapytaniu mogę pobierać dane z wielu zasobów, aby skonstruować odpowiedź (pomyślmy o połączeniu SQL), więc nie będę odsyłał identyfikatorów URI, ale rzeczywiste dane. Problem polega na tym, że dane nie będą reprezentowane w zasobie, więc zawsze będę musiał zwrócić dane. Wydaje mi się to oczywistym przypadkiem konieczności POST.

-

Minęło trochę czasu, a mój oryginalny post był nieco niechlujny, więc pomyślałem, że zaktualizuję.

GET to intuicyjny wybór do zwracania większości rodzajów danych, kolekcji zasobów REST, danych strukturalnych zasobu, a nawet pojedynczych ładunków (obrazów, dokumentów itp.).

POST to metoda catchall na wszystko, co nie pasuje do GET, PUT, DELETE itp.

W tym momencie myślę, że proste wyszukiwania, filtrowanie intuicyjnie mają sens przez GET. Wyszukiwanie złożone zależy od osobistych preferencji, szczególnie jeśli dodajesz funkcje agregacji, korelacje krzyżowe (sprzężenia), przekształcanie formatów itp. Argumentowałbym, że parametry GET nie powinny być zbyt długie i jest to duże zapytanie (jednak jest ono ustrukturyzowane ) często ma większy sens jako treść żądania POST.

Rozważam także aspekt korzystania z interfejsu API. Zasadniczo chcę, aby większość metod była jak najłatwiejsza w obsłudze i intuicyjna. Będę wypychać połączenia, które są bardziej elastyczne (a zatem bardziej złożone) do POST i na inny identyfikator URI zasobu, szczególnie jeśli jest to niezgodne z zachowaniem innych zasobów REST w tym samym interfejsie API.

Tak czy inaczej, spójność jest prawdopodobnie ważniejsza niż to, czy przeprowadzasz wyszukiwanie w GET, czy POST.

Mam nadzieję że to pomoże.


1
Ponieważ REST ma na celu wyodrębnienie podstawowej implementacji (np. - zasób niekoniecznie jest wierszem w bazie danych lub plikiem na dysku twardym, ale może być czymkolwiek ), nie wiem, czy użycie POST ma sens Uzyskaj, jeśli chodzi o wykonywanie sprzężeń SQL. Załóżmy, że masz tabelę szkół i tabelę dzieci i chcesz klasę (jedna szkoła, wiele dzieci). Możesz łatwo zdefiniować wirtualny zasób i GET /class?queryParams. Z punktu widzenia użytkownika „klasa” zawsze była rzeczą i nie trzeba było wykonywać żadnych dziwnych połączeń SQL.
stevendesu,

Nie ma różnicy między „filtrowaniem” a „wyszukiwaniem”.
Nicholas Shanks

1
Tak, istnieje filtr oparty na istniejących polach. Wyszukiwanie może zawierać znacznie bardziej złożone wzorce, łączenie pól, obliczanie wartości
sąsiednich

@stevendesu dokładnie, dlatego używam POST do obu (tworzenie wyszukiwania) :-)
ymajoros

@ymajoros O ile nie zapisujesz gdzieś wyszukiwanych haseł i wyników wyszukiwania, nie wiem, czy test POST ma sens semantyczny. Kiedy przeprowadzasz wyszukiwanie, żądasz informacji, nie podajesz żadnych nowych informacji, które chcesz zachować.
stevendesu

10

W REST definicja zasobów jest bardzo szeroka. Naprawdę jednak chcesz połączyć pewne dane.

  • Warto pomyśleć o zasobach wyszukiwania jako zasobach kolekcji. Parametry zapytania, zwane czasem przeszukiwalną częścią identyfikatora URI, zawężają zasób do elementów, którymi zainteresowany jest klient.

Na przykład główny identyfikator URI Google wskazuje na zbiór zasobów „linków do każdej witryny w Internecie”. Parametry zapytania zawężają to do witryn, które chcesz zobaczyć.

(URI = uniwersalny identyfikator zasobu, którego URL = uniwersalny lokalizator zasobów, gdzie znany „http: //” jest domyślnym formatem identyfikatora URI. Zatem URL jest lokalizatorem, ale w REST dobrze jest uogólnić to na identyfikator zasobu Ludzie używają ich jednak zamiennie).

  • Ponieważ zasób, którego szukasz w tym przykładzie, to zbiór zadań, warto szukać za pomocą

GET site / jobs? Type = blah & location = here & etc = etc

(powrót) {jobs: [{job: ...}]}

A następnie użyj POST, czyli czasownika dołączającego lub procesowego, aby dodać nowe elementy do tej kolekcji:

Witryna / zadania POST

{praca: ...}

  • Zauważ, że jobw każdym przypadku jest to ta sama struktura dla obiektu. Klient może UZYSKAĆ ​​kolekcję zadań, używając parametrów zapytania w celu zawężenia wyszukiwania, a następnie użyć tego samego formatu dla jednego z elementów, aby opublikować nowe zadanie. Lub może zabrać jeden z tych elementów i PUT do swojego identyfikatora URI, aby go zaktualizować.

  • W przypadku naprawdę długich lub skomplikowanych ciągów zapytań konwencja pozwala zamiast tego wysyłać je jako żądania POST. Sparuj parametry zapytania jako pary nazwa / wartość lub zagnieżdżone obiekty w strukturze JSON lub XML i wyślij je w treści żądania. Na przykład, jeśli zapytanie zawiera zagnieżdżone dane zamiast kilku par nazwa / wartość. Specyfikacja HTTP dla POST opisuje ją jako czasownik dołączający lub procesowy. (Jeśli chcesz popłynąć pancernikiem przez lukę w REST, użyj POST.)

Użyłbym tego jednak jako planu awaryjnego.

To, co tracisz, gdy to robisz, to: a) GET jest nullipotentny - to znaczy nic nie zmienia - POST nie. Jeśli więc połączenie się nie powiedzie, oprogramowanie pośrednie nie będzie automatycznie ponawiać próby ani buforować wyników oraz 2) z parametrami wyszukiwania w treści, nie można już wycinać i wklejać identyfikatora URI. Oznacza to, że identyfikator URI nie jest konkretnym identyfikatorem poszukiwanego wyszukiwania.

Aby odróżnić „Utwórz” od „Szukaj”. Istnieje kilka opcji zgodnych z praktyką REST:

  • Możesz to zrobić w URI, dodając coś do nazwy kolekcji, np. Poszukiwanie pracy zamiast zadań. Oznacza to, że traktujesz kolekcję wyszukiwania jako osobny zasób.

  • Ponieważ semantyka POST jest procesem dołączania LUB, można wyszukiwać ciała wyszukiwania z ładunkiem. Jak {job: ...} vs. {search: ...}. Zadaniem logiki POST jest odpowiednie opublikowanie lub przetworzenie.

To właściwie preferencja dotycząca projektowania / implementacji. Nie sądzę, że istnieje jasna konwencja.

Tak więc, jak już zaplanowałeś, pomysł polega na zdefiniowaniu zasobu kolekcji jobs

strona / oferty pracy

Wyszukaj za pomocą parametrów zapytania GET +, aby zawęzić wyszukiwanie. Długie lub ustrukturyzowane zapytania o dane trafiają do treści POST (być może do oddzielnej kolekcji wyszukiwania). Utwórz za pomocą POST, aby dołączyć do kolekcji. I zaktualizuj za pomocą PUT do konkretnego identyfikatora URI.

(FWIW konwencja stylu z identyfikatorami URI polega na użyciu wszystkich małych liter ze słowami oddzielonymi łącznikami. Ale to nie znaczy, że musisz to zrobić w ten sposób.)

(Powinienem również powiedzieć, że z twojego pytania jasno wynika, że ​​jesteś daleko na tej drodze. Przeliterowałem pewne rzeczy, aby je uporządkować, ale twoje pytanie już dotyczyło większości problemów semantycznych w tym odpowiedź. Po prostu łączyłem to z konwencją i praktyką.)


To ciekawy pomysł - nie rozważyłbym użycia ładunku do rozróżnienia. To prawie wydaje się trochę podstępne! Ale wydaje mi się, że schemat URI tak naprawdę nie zawiera żadnych czasowników - to typ zapytania definiuje czasownik. Może ładunek jest semantycznie bliższy typowi żądania niż identyfikator URI. Jedyny problem dotyczy - czy jest przejrzysty dla użytkownika interfejsu API?
Rob Baillie

Jeśli chodzi o implementację (używamy Node i Express), może to oznaczać, że routetak naprawdę nie jest w stanie obsłużyć wyboru przetwarzania. Muszę rzucić na to okiem ...
Rob Baillie

Mam takie samo przeczucie, że oddzielenie go przez URI wydaje się czystsze. W pewnym sensie chodzę tam iz powrotem; to wezwanie do sądu. Jednak semantyka HTTP pozwoliłaby na umieszczenie go w treści. Lubię powiedzieć, że REST jest wzorowany na World Wide Web, a WWW został zbudowany za pomocą GET i POST.
Rob

8

Zazwyczaj używam zapytań OData, działają one jako wywołanie GET, ale pozwalają ci ograniczyć zwracane właściwości i filtrować je.

Używasz tokenów, takich jak $select=i, $filter=więc otrzymujesz identyfikator URI, który wygląda mniej więcej tak:

/users?$select=Id,Name$filter=endswith(Name, 'Smith')

Można również zrobić przy użyciu stronicowania $skipi $topi zamawiania.

Aby uzyskać więcej informacji, sprawdź OData.org . Nie określiłeś, jakiego języka używasz, ale jeśli jest to ASP.NET, platforma WebApi obsługuje zapytania OData - dla innych (PHP itp.) Prawdopodobnie są biblioteki, których możesz użyć do przetłumaczenia ich na zapytania do bazy danych.


6
Ciekawe łącze, na które warto spojrzeć, ale czy rozwiązuje ono podstawowy opisany problem, polegający na tym, że żądania GET nie obsługują więcej niż 2000 znaków w ciągu zapytania i czy jest całkiem możliwe, że zapytanie może być znacznie dłuższe?
Rob Baillie

@RobBaillie Nie sądzę, ponieważ nadal jest to wywołanie GET z ciągiem zapytania. Sugeruję użycie OData, gdziekolwiek to możliwe, ponieważ jest to standard do kwerendy w źródłach danych w sieci, a ponieważ kilka (jeśli w ogóle) zapytanie musi być tak złożone, że nie można go dopasować do zapytania o długości 2000 znaków, utwórz określoną punkt końcowy, do którego dzwonisz GET
Trevor Pilley

Czy możesz wyjaśnić swoje podejście do „określonego punktu końcowego, do którego nawiązujesz połączenie GET”? Jak możesz sobie wyobrazić ten punkt końcowy?
Rob Baillie

@RobBaillie na pewno - znowu nie jestem pewien, jakiej technologii używasz, ale w ASP.NET stworzyłbym konkretny kontroler o nazwie JobsNearMeAddedInTheLast7Dayslub cokolwiek innego, aby obudować zapytanie, które jest zbyt długie / złożone dla OData, a następnie ujawniam je tylko za pomocą wywołań GET .
Trevor Pilley

1
Widzę. Kolejna interesująca myśl, która prawdopodobnie ma pewne nogi, choć nie jestem pewien, czy to pomogłoby w moim konkretnym przypadku - wyszukiwanie aspektowe z wieloma rodzajami aspektów i wieloma możliwymi wartościami aspektów
Rob Baillie

5

Jednym podejściem do rozważenia jest traktowanie zestawu możliwych zapytań jako zasobu kolekcji, np /jobs/filters.

POSTwnioski do tego zasobu, z parametrów kwerendy w organizmie, albo będzie utworzyć nowy zasób lub wyznaczyć istniejący odpowiednik filtra i powrotu URL zawierający jego ID: /jobs/filters/12345.

Identyfikator może być następnie wykorzystane w żądaniu GET dla zadań: /jobs?filter=12345. Kolejne GETżądania dotyczące zasobu filtru zwrócą definicję filtra.

Zaletą tego podejścia jest to, że uwalnia cię od formatu parametru zapytania do definicji filtra, potencjalnie zapewniając więcej mocy do definiowania złożonych filtrów. Warunki OR są jednym z przykładów, które mogę wymyślić, które są trudne do spełnienia za pomocą ciągów zapytań.

Wadą tego podejścia jest utrata czytelności adresu URL (chociaż można to złagodzić, pobierając definicję przez GETżądanie zasobu filtru). Z tego powodu możesz również chcieć obsługiwać ten sam lub podzbiór parametrów zapytania w /jobszasobie, tak jak w przypadku zasobu filtrującego. Można to wykorzystać do krótszych zapytań. Jeśli ta funkcja jest dostępna, aby zachować pamięć podręczną między dwoma typami filtrowania, podczas korzystania z parametrów zapytania w /jobszasobie implementacja powinna wewnętrznie utworzyć / ponownie użyć zasobu filtru i zwrócić wartość 302lub 303status wskazujący adres URL w postaci /jobs?filter=12345.


Moja pierwsza reakcja na to jest taka, że ​​chociaż jest to dobra informacja, tak naprawdę jest to tylko wariant odpowiedzi udzielonej przez @burninggramma. Zasadniczo jest to „stwórz nowy byt o nazwie filtr / wyszukiwanie, zadzwoń, aby go utworzyć, a następnie wywołaj, aby go pobrać”. Odmiana polega na tym, że wywołanie w celu jej odzyskania przypomina połączenie w celu zastosowania go do kolekcji. Ciekawy. Jednak odpowiedź na twoje i Burngramma cierpi z powodu tego samego problemu - nie chcę tworzyć filtrów. Będzie ich ogromna liczba i nie trzeba ich przechowywać, chyba że w celu zachowania implementacji RESTful.
Rob Baillie

2
Oczywiście parametry zapytania są najlepszym rozwiązaniem, ale twoje pytanie dotyczy konkretnego sposobu postępowania z definicjami filtrów dłużej niż limit adresów URL narzucony przez niektóre serwery. Aby obejść limit długości, albo trzeba w jakiś sposób skompresować ciąg zapytania, albo użyć metody żądania, która obsługuje określenie ciała o dowolnej długości. Jeśli nie chcesz traktować filtrów jako zasobu, po prostu obsługuj niespokojny interfejs, w którym definicje filtrów są POST. Utracisz pamięć podręczną, ale jeśli dane są wystarczająco niestabilne, i tak nie skorzysta na buforowaniu.
pgraham

Możesz przezwyciężyć potrzebę przechowywania filtrów, po prostu ... nie przechowując ich. Nic o REST nie gwarantuje trwałości. Możesz złożyć wniosek GET /jobs/37i otrzymać wynik, a następnie ktoś usunie zasób, a 2 sekundy później to samo żądanie zwróci 404. Podobnie, jeśli zostaniesz POST /searchesprzekierowany do wyniku wyszukiwania (wyszukiwanie zostanie utworzone, a otrzymasz 201 z Lokalizacja nagłówka zasobu), 2 sekundy później wynik może zostać usunięty z pamięci i trzeba go zregenerować. Nie ma potrzeby przechowywania długoterminowego.
stevendesu,

5

To stara odpowiedź, ale nadal mogę trochę przyczynić się do dyskusji. Bardzo często obserwowałem nieporozumienie dotyczące REST, RESTful i architektury. RESTful nigdy nie wspomina nic o wyszukiwaniu NIE, nie ma nic w RESTful o architekturze, to zestaw zasad lub kryteriów projektowych.

Aby lepiej opisać wyszukiwanie, musimy porozmawiać w szczególności o architekturze, a ta, która lepiej pasuje, to architektura zorientowana na zasoby (ROA).

W RESTful istnieją zasady projektowania, idempotent nie oznacza, że ​​wynik nie może się zmienić, jak czytam w niektórych odpowiedziach, oznacza to, że wynik niezależnego żądania nie zależy od tego, ile razy zostanie wykonany. Może się zmieniać, wyobraźmy sobie, że ciągle aktualizuję bazę danych, zasilając ją niektórymi danymi, które są obsługiwane przez RESTful API, wykonanie tego samego GET może zmienić wynik, ale nie zależy to od tego, ile razy zostało wykonane. Jeśli jestem w stanie zamrozić świat, oznacza to, że nie ma stanu, transformacji ani niczego w usłudze, gdy żądam zasobu, który prowadzi do innego wyniku.

Z definicji zasób to wszystko, co jest ważne, aby można je było traktować jako rzecz samą w sobie.

W architekturze zorientowanej na zasoby (nazwijmy to teraz ROA dla zwięzłości) skupiamy się na zasobie, który może być wieloma rzeczami:

  • Wersja dokumentu
  • Ostatnia zaktualizowana wersja dokumentu
  • Wynik pochodzący z wyszukiwania
  • Lista obiektów
  • Pierwszy artykuł kupiłem w e-commerce

To, co czyni go wyjątkowym pod względem zasobów, to adresowalność, co oznacza, że ​​ma tylko jeden identyfikator URI

W ten sposób wyszukiwanie idealnie pasuje do RESTful, biorąc pod uwagę ROA . Musimy użyć GET, ponieważ zakładam, że twoje wyszukiwanie jest normalnym wyszukiwaniem i niczego nie zmienia, więc jest idempotentne (nawet jeśli zwraca różne rzeczy w zależności od dodanych nowych elementów). Jest w tym zamieszanie, ponieważ mogę trzymać się RESTful, a nie ROA, oznacza to, że mogę podążać za wzorem, który tworzy wyszukiwanie i zwracać różne rzeczy o tych samych parametrach, ponieważ nie używam zasady adresowalności ROA. W jaki sposób? Cóż, jeśli wyślesz filtry wyszukiwania w treści lub nagłówku, zasób nie będzie ADRESOWALNY.

Możesz znaleźć zasady dokładnie tego, co dokładnie i URI w oryginalnym dokumencie W3:

https://www.w3.org/DesignIssues/Axioms

Każdy adres URL w tej architekturze musi być opisowy. Jest to konieczne, jeśli postępujesz zgodnie z zasadami, aby zająć się wszystkim w URI, oznacza to, że możesz użyć / (ukośnik), aby oddzielić wszystko, czego potrzebujesz lub parametry zapytania. Wiemy, że istnieją ograniczenia, ale jest to wzorzec architektury.

Zgodnie z wzorcem ROA w RESTful wyszukiwanie nie jest większe niż jakikolwiek inny zasób, jedyną różnicą jest to, że zasoby pochodzą z obliczeń zamiast bezpośredniego związku z samym obiektem. W oparciu o zasadę mógłbym zająć się i uzyskać prostą usługę obliczeń arytmetycznych w oparciu o następujący wzorzec:

http://myapi.com/sum/1/2

Tam, gdzie sumę 1 i 2 można modyfikować, ale wynik obliczeń jest unikalny i można go adresować, za każdym razem, gdy dzwonię z tymi samymi parametrami, uzyskuję to samo i nic się nie zmienia w serwisie. Resouce / sum / 1/2 i / subtract / 5/4 doskonale trzymają się zasad.


3

GET jest w porządku, jeśli masz kolekcję statyczną, która zawsze zwraca te same wyniki (reprezentację) dla jednego identyfikatora URI. Oznacza to również, że dane generujące te reprezentacje nigdy nie są zmieniane. Źródłem jest baza danych tylko do odczytu.

Otrzymywanie przez GET różnych wyników dla tego samego identyfikatora URI narusza idempotencja / bezpieczeństwo i zasadę CoolURI, w związku z czym nie jest w stanie RESTful . Czasami idempotentne czasowniki mogą być zapisywane w bazie danych, ale nigdy nie mogą wpływać na reprezentację.

Wspólne wyszukiwanie rozpoczyna się od żądania POST, które zwraca odniesienie do wyniku. Generuje wynik (jest nowy i można go pobrać z kolejnym GET). Ten wynik może być hierarchiczny (dalsze odwołania do identyfikatorów URI, które można uzyskać) i może ponownie wykorzystywać elementy wcześniejszych wyszukiwań, jeśli ma to sens dla aplikacji.

Nawiasem mówiąc, wiem, że ludzie robią to inaczej. Nie musisz mi wyjaśniać, jak wygodne może być naruszenie REST.


Aaaaaaaah - więc tak to powinno działać! Dzięki!
Rob Baillie,

1
Idempotencja nie oznacza, że ​​musi zawsze zwracać dokładnie to samo, musi zwracać to samo, jeśli NIC się nie zmieni. Wyszukiwanie można uznać za wynik obliczeń i jest to sam zasób.
Maximiliano Rios,

Idempotencja faktycznie oznacza, że ​​wynik pozostaje ten sam. Możesz, i jest to wykonalne, używać kontroli pamięci podręcznej. I oczywiście możesz użyć DELETE, który zakłóca późniejsze GET-y. Jeśli jednak agent musi zachować wiedzę o wewnętrznym działaniu aplikacji, nie jest to już RESTful. Powyżej mówiłem o najbardziej ekstremalnym pomyśle REST. W praktyce ludzie mogą naruszać wiele jego aspektów. Płacą cenę, gdy pamięci podręczne nie są już wydajnie buforowane.
Martin Sugioarto,

„Idempotencja faktycznie oznacza, że ​​wynik pozostaje taki sam.” ... po żądaniu. myślę, że chodzi o to, że żądanie nie zmienia danych.
AndreiMotinga
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.