Pierwszy
Zgodnie z RFC 3986 §3.4 (Jednolite identyfikatory zasobów § (Składniki składniowe) | Zapytanie
3.4 Zapytanie
Komponent zapytania zawiera dane niehierarchiczne, które wraz z danymi w komponencie ścieżki (sekcja 3.3) służą do identyfikacji zasobu w ramach schematu identyfikatora URI i uprawnień do nazewnictwa (jeśli istnieją).
Komponenty zapytania służą do wyszukiwania danych niehierarchicznych; jest kilka rzeczy bardziej zhierarchizowanych niż drzewo genealogiczne! Ergo - niezależnie od tego, czy uważasz, że jest to „REST-y”, czy nie - w celu zachowania zgodności z formatami, protokołami i ramami oraz do opracowywania systemów w Internecie nie wolno używać ciągu zapytania do identyfikacji tych informacji.
REST nie ma nic wspólnego z tą definicją.
Przed udzieleniem odpowiedzi na konkretne pytania parametr zapytania „szukaj” jest źle nazwany. Lepiej byłoby traktować segment zapytania jako słownik par klucz-wartość.
Łańcuch zapytania można lepiej zdefiniować jako
?first_name={firstName}&last_name={lastName}&birth_date={birthDate}
itp.
Aby odpowiedzieć na twoje konkretne pytania
1) Który projekt API jest bardziej RESTful i dlaczego? Semantycznie mają na myśli i zachowują się w ten sam sposób. Ostatnim zasobem w URI jest „potomek”, co skutecznie sugeruje, że klient działa na zasobu potomnym.
Nie sądzę, że jest to tak jasne, jak się wydaje.
Żaden z tych interfejsów zasobów nie jest w stanie RESTful. Ważnym warunkiem dla relaksującego stylu jest to, że przemiany Zastosowanie państwowe muszą być przekazywane z serwera jako hipermediów. Ludzie pracowali nad strukturą URI, aby uczynić je w jakiś sposób „RESTful URI”, ale oficjalna literatura na temat REST naprawdę niewiele ma na ten temat do powiedzenia. Moje osobiste zdanie jest takie, że wiele meta-dezinformacji na temat REST zostało opublikowanych z zamiarem przełamania starych, złych nawyków. (Budowa prawdziwie „RESTful” to w rzeczywistości sporo pracy. Przemysł przeszedł do „REST” i zaspokoił niektóre ortogonalne obawy bezsensownymi kwalifikacjami i ograniczeniami.)
Literatura REST mówi, że jeśli zamierzasz używać HTTP jako protokołu aplikacji, musisz przestrzegać formalnych wymagań specyfikacji protokołu i nie możesz „tworzyć HTTP podczas pracy i nadal deklarować, że używasz HTTP” ; jeśli zamierzasz używać identyfikatorów URI do identyfikowania swoich zasobów, musisz przestrzegać formalnych wymagań specyfikacji dotyczących URI / adresów URL.
Twoje pytanie jest adresowane bezpośrednio w RFC3986 §3.4, które zamieściłem powyżej. Najważniejsze w tej kwestii jest to, że chociaż zgodny identyfikator URI jest niewystarczający, aby uznać interfejs API za „RESTful”, jeśli chcesz, aby Twój system rzeczywiście był „RESTful” i używasz HTTP i URI, nie możesz zidentyfikować danych hierarchicznych za pomocą ciąg zapytania, ponieważ:
3.4 Zapytanie
Komponent zapytania zawiera dane niehierarchiczne
... to takie proste.
2) Jakie są zalety i wady dla każdego pod względem zrozumiałości z perspektywy klienta i łatwości konserwacji z perspektywy projektanta.
„Zaletami” pierwszych dwóch jest to, że są na właściwej ścieżce . „Wadą” trzeciego jest to, że wydaje się całkowicie błędny.
Jeśli chodzi o twoją zrozumiałość i łatwość konserwacji, są one zdecydowanie subiektywne i zależą od poziomu zrozumienia twórcy klienta i elementów projektu projektanta. Specyfikacja URI jest ostateczną odpowiedzią na to, w jaki sposób powinny być formatowane URI. Dane hierarchiczne powinny być reprezentowane na ścieżce wraz z parametrami ścieżki. Dane niehierarchiczne powinny być reprezentowane w zapytaniu. Fragment jest bardziej skomplikowany, ponieważ jego semantyka zależy w szczególności od rodzaju mediów żądanej reprezentacji. Aby zająć się częścią „zrozumiałości” twojego pytania, postaram się przetłumaczyć dokładnie to, co mówią twoje pierwsze dwa identyfikatory URI. Następnie spróbuję przedstawić to, co mówisz, że próbujesz osiągnąć za pomocą prawidłowych identyfikatorów URI.
Tłumaczenie dosłownych identyfikatorów URI na ich znaczenie semantyczne
/myservice/api/v1/grandparents/{grandparentID}/parents/children?search={text}
To mówi dla rodziców dziadków, że ich dziecko ma search={text}
to, co powiedziałeś z URI, jest spójne tylko wtedy, gdy szukasz rodzeństwa dziadka. Z „dziadkami, rodzicami, dziećmi” znaleźliście „dziadka”, który dorastał z pokoleniem do swoich rodziców, a następnie powrócił do pokolenia „dziadków”, patrząc na dzieci rodziców.
/myservice/api/v1/parents/{parentID}/children?search={text}
Mówi to, że dla rodzica zidentyfikowanego przez {parentID}, znajdź jego dziecko mające ?search={text}
To jest bliższe do poprawienia tego, czego chcesz, i reprezentuje relację rodzic-dziecko, które prawdopodobnie może być użyte do modelowania całego API. Aby modelować to w ten sposób, klient jest obciążony rozpoznaniem, że jeśli mają „dziadka”, to istnieje warstwa pośrednicząca między posiadanym identyfikatorem a częścią wykresu rodzinnego, którą chcą zobaczyć. Aby znaleźć „dziecko” według „dziadka”, możesz zadzwonić do /parents/{parentID}/children
serwisu, a następnie wskazać dziecko, które zostanie zwrócone, poszukaj dzieci w poszukiwaniu identyfikatora osoby.
Implementacja twoich wymagań jako identyfikatorów URI
Jeśli chcesz modelować bardziej rozszerzalny identyfikator zasobu, który może chodzić po drzewie, mogę wymyślić kilka sposobów na osiągnięcie tego.
1) Pierwszy, o którym już wspomniałem. Reprezentuj wykres „Ludzie” jako strukturę złożoną. Każda osoba ma odniesienie do pokolenia nad nią poprzez ścieżkę Rodziców i do pokolenia pod nim poprzez ścieżkę Dzieci.
/Persons/Joe/Parents/Mother/Parents
byłby sposobem na złapanie matczynych dziadków Joe.
/Persons/Joe/Parents/Parents
byłby sposobem na złapanie wszystkich dziadków Joe.
/Persons/Joe/Parents/Parents?id={Joe.GrandparentID}
złapałby dziadka Joe, który miałby przy sobie identyfikator.
i wszystko to miałoby sens (należy pamiętać, że może tu wystąpić kara wydajności w zależności od zadania przez wymuszenie dfs na serwerze z powodu braku identyfikacji gałęzi we wzorcu „Rodzice / Rodzice / Rodzice”). zdolność do obsługi dowolnej liczby pokoleń. Jeśli z jakiegoś powodu chcesz spojrzeć na 8 pokoleń, możesz to przedstawić jako
/Persons/Joe/Parents/Parents/Parents/Parents/Parents/Parents/Parents/Parents?id={Joe.NotableAncestor}
ale prowadzi to do drugiej dominującej opcji reprezentowania tych danych: poprzez parametr ścieżki.
2) Użyj parametrów ścieżki do „zapytania do hierarchii”. Możesz opracować następującą strukturę, aby zmniejszyć obciążenie konsumentów i nadal mieć sensowny interfejs API.
Aby spojrzeć wstecz na 147 pokoleń, reprezentacja tego identyfikatora zasobu za pomocą parametrów ścieżki pozwala to zrobić
/Persons/Joe/Parents;generations=147?id={Joe.NotableAncestor}
Aby zlokalizować Joe od jego pradziadka, możesz spojrzeć w dół wykresu znanej liczby pokoleń identyfikatora Joe.
/Persons/JoesGreatGrandparent/Children;generations=3?id={Joe.Id}
Najważniejszą rzeczą w tych podejściach jest to, że bez dalszych informacji w identyfikatorze i żądaniu należy spodziewać się, że pierwszy identyfikator URI pobiera od osoby Joe pokolenia 147 o identyfikatorze Joe.NotableAncestor. Powinieneś spodziewać się, że drugi odzyska Joe. Załóżmy, że tak naprawdę chcesz, aby klient wywołujący mógł pobrać cały zestaw węzłów i ich relacje między osobą główną a ostatecznym kontekstem twojego identyfikatora URI. Możesz to zrobić przy użyciu tego samego identyfikatora URI (z pewną dodatkową dekoracją) i ustawiając opcję Akceptuj text/vnd.graphviz
na żądanie, która jest typem nośnika zarejestrowanym przez IANA do .dot
reprezentacji wykresu. Dzięki temu zmień identyfikator URI na
/Persons/Joe/Parents;generations=147?id={Joe.NotableAncestor.Id}#directed
z nagłówkiem żądania HTTP
Accept: text/vnd.graphviz
, dzięki czemu klienci mogą dość wyraźnie komunikować, że chcą skierowanego wykresu hierarchii pokoleniowej między Joe a 147 pokoleniami wcześniej, gdy 147. pokolenie przodków zawiera osobę zidentyfikowaną jako „godny uwagi przodek” Joe'ego.
Nie jestem pewien, czy text / vnd.graphviz ma jakąś predefiniowaną semantykę dla swojego fragmentu; nie mogłem znaleźć żadnej w poszukiwaniu instrukcji. Jeśli ten typ nośnika faktycznie zawiera wstępnie zdefiniowane informacje o fragmencie, należy zastosować jego semantykę, aby utworzyć zgodny identyfikator URI. Ale jeśli te semantyki nie są wstępnie zdefiniowane, specyfikacja URI stwierdza, że semantyka identyfikatora fragmentu jest nieograniczona i zamiast tego jest zdefiniowana przez serwer, dzięki czemu użycie jest prawidłowe.
3) Do czego tak naprawdę używane są ciągi zapytania oprócz „filtrowania” zasobów? Jeśli wybierzesz pierwsze podejście, parametr filtru zostanie osadzony w samym URI jako parametr ścieżki zamiast parametru ciągu zapytania.
Wydaje mi się, że już całkowicie pobiłem to na śmierć, ale ciągi zapytań nie służą do „filtrowania” zasobów. Służą do identyfikacji Twojego zasobu na podstawie danych niehierarchicznych. Jeśli przejrzałeś swoją hierarchię swoją ścieżką, idąc
/person/{id}/children/
i chcesz zidentyfikować określone dziecko lub określony zestaw dzieci, użyjesz atrybutu, który dotyczy zestawu, który identyfikujesz i umieścisz go w zapytaniu.