Szukam rozsądnego sposobu reprezentowania wyszukiwań jako RESTful URL-i.
Konfiguracja: Mam dwa modele, Samochody i Garaże, w których Samochody mogą być w Garażach. Moje adresy URL wyglądają następująco:
/car/xxxx
xxx == car id
returns car with given id
/garage/yyy
yyy = garage id
returns garage with given id
Samochód może istnieć samodzielnie (stąd / car) lub może istnieć w garażu. Jaki jest właściwy sposób reprezentowania, powiedzmy, wszystkich samochodów w danym garażu? Coś jak:
/garage/yyy/cars ?
Co powiesz na połączenie samochodów w garażu yyy i zzz?
Jaki jest właściwy sposób reprezentowania wyszukiwania samochodów o określonych atrybutach? Powiedz: pokaż mi wszystkie niebieskie sedany z 4 drzwiami:
/car/search?color=blue&type=sedan&doors=4
czy raczej powinno to być / cars?
Użycie „wyszukiwania” wydaje się tam niewłaściwe - jaki jest lepszy sposób / termin? Powinno to być po prostu:
/cars/?color=blue&type=sedan&doors=4
Czy parametry wyszukiwania powinny być częścią PATHINFO lub QUERYSTRING?
Krótko mówiąc, szukam wskazówek dotyczących projektowania adresów URL REST między modelami i wyszukiwania.
[Aktualizacja] Podoba mi się odpowiedź Justina, ale on nie obejmuje przypadku wyszukiwania wielu pól:
/cars/color:blue/type:sedan/doors:4
czy jakoś tak. Jak idziemy
/cars/color/blue
w przypadku wielu pól?
/cars
i/car
nie jest semantyczne i dlatego jest to zły pomysł. Zawsze używaj liczby mnogiej, jeśli w tej kategorii jest więcej niż jeden element.Odpowiedzi:
Do wyszukiwania użyj kwerend. Jest to całkowicie RESTful:
Zaletą regularnych zapytań jest to, że są one standardowe i szeroko rozumiane oraz że można je generować z form-get.
źródło
/cars?color=whatever
./cars?color=blue&type=sedan&doors=4/engines
Nie zadziała/cars?param=value
służy do prostego filtrowania na liście samochodów i/cars/search?param=value
do tworzenia wyszukiwania (z ou bez wytrwałości), w którym wynik może zawierać punktację wyszukiwania, kategoryzację itp. Możesz także utworzyć / usunąć wyszukiwanie nazwane, takie jak/cars/search/mysearch
. Spójrz na to: stackoverflow.com/a/18933902/1480391Projekt RESTful pretty URL polega na wyświetlaniu zasobu opartego na strukturze (struktura katalogowa, data: artykuły / 2005/5/13, obiekt i jego atrybuty, ..), ukośnik
/
wskazuje strukturę hierarchiczną,-id
zamiast tego użyj .Struktura hierarchiczna
Osobiście wolałbym:
Jeśli użytkownik usunie
/car-id
część, wyświetlacars
podgląd - intuicyjny. Użytkownik dokładnie wie, gdzie jest na drzewie, na co patrzy. Od pierwszego spojrzenia wie, że garaże i samochody są ze sobą powiązane./car-id
oznacza również, że należy do siebie w przeciwieństwie do/car/id
.Badawczy
Wyszukiwanie jest w porządku , ponieważ jest tylko twoje preferencje, co należy wziąć pod uwagę. Zabawne jest to, że dołączasz do wyszukiwania (patrz poniżej).
Lub w zasadzie wszystko, co nie jest cięciem, jak wyjaśniono powyżej.
Formuła:,
/cars[?;]color[=-:]blue[,;+&]
* chociaż nie użyłbym&
znaku, ponieważ na pierwszy rzut oka nie można go rozpoznać po tekście.Listy opcji
możliwe funkcje?
Neguj ciągi wyszukiwania (!)
Aby wyszukać dowolne samochody, ale nie czarne i czerwone :
?color=!black,!red
color:(!black,!red)
Wyszukiwania Dołączył
Szukaj czerwone lub niebieskie lub czarne samochody z 3 bram w garażach id 1..20 lub 101..103 lub 999 , ale nie 5
/garage[id=1-20,101-103,999,!5]/cars[color=red,blue,black;doors=3]
Następnie można skonstruować bardziej złożonych zapytań. (Spójrz na dopasowanie atrybutów CSS3 pod kątem idei dopasowania podciągów. Np. Wyszukiwanie użytkowników zawierających „słupek”
user*=bar
.)Wniosek
W każdym razie, to może być najważniejszą częścią dla ciebie, ponieważ można to zrobić jak chcesz po wszystkim, po prostu pamiętać, że relaksującego URI oznacza strukturę, która jest łatwo zrozumiałe, np katalog podobny
/directory/file
,/collection/node/item
, daty/articles/{year}/{month}/{day}
.. A jeśli pominąć którykolwiek z ostatnich segmentów, od razu wiesz, co dostajesz.Więc ... wszystkie te znaki są dozwolone niekodowane :
a-zA-Z0-9_.-~
zazwyczaj dozwolone zarówno zakodowane, jak i nie, oba zastosowania są wtedy równoważne.
$-_.+!*'(),
;/?:@=&
Mogą być używane niezakodowane do celów, które reprezentują, w przeciwnym razie muszą zostać zakodowane.
niebezpieczne:
<>"#%{}|\^~[]`
Dlaczego niebezpieczne i dlaczego należy raczej zakodować: RFC 1738 patrz 2.2
Zobacz także RFC 1738 # strona-20, aby uzyskać więcej klas postaci.
RFC 3986 patrz 2.2
Pomimo tego, co powiedziałem wcześniej, tutaj jest wspólne rozróżnienie delimetrów, co oznacza, że niektóre „są” ważniejsze niż inne.
:/?#[]@
!$&'()*+,;=
Więcej lektur:
Hierarchia: patrz 2.3 , patrz 1.2.3
składnia parametru ścieżki adresu URL
atrybut CSS3 zgodny z
IBM: RESTful Web Services - podstawy
Uwaga: RFC 1738 został zaktualizowany przez RFC 3986
źródło
POST
. Również inne pomysły, które podałeś w swojej odpowiedzi, są bardzo znaczące. Dziękuję bardzo!;
w przeciwieństwie do&
czytelności? Bo jeśli tak, to myślę, że tak naprawdę wolałbym,&
ponieważ jest to bardziej powszechny ogranicznik ... prawda? :) Dzięki!&
jako separator jest znany tylko programistom. Rodzice, dziadkowie i niewykształcona populacja akceptują ograniczniki, jak to jest używane we wspólnym tekście pisanym.Chociaż posiadanie parametrów na ścieżce ma pewne zalety, istnieją, według IMO, pewne czynniki przeważające.
Nie wszystkie znaki potrzebne do wyszukiwania są dozwolone w adresie URL. Większość znaków interpunkcyjnych i Unicode musiałaby być zakodowana w adresie URL jako parametr ciągu zapytania. Walczę z tym samym problemem. Chciałbym użyć XPath w adresie URL, ale nie cała składnia XPath jest zgodna ze ścieżką URI. W przypadku prostych ścieżek
/cars/doors/driver/lock/combination
wskazane byłoby zlokalizowanie elementu „combination
” w dokumencie XML drzwi kierowcy. Ale/car/doors[id='driver' and lock/combination='1234']
nie jest taki przyjazny.Istnieje różnica między filtrowaniem zasobu na podstawie jednego z jego atrybutów a określaniem zasobu.
Na przykład od
/cars/colors
zwraca listę wszystkich kolorów dla wszystkich samochodów (zwrócony zasób to zbiór obiektów kolorowych)/cars/colors/red,blue,green
zwróci listę obiektów kolorowych, które są czerwone, niebieskie lub zielone, a nie kolekcję samochodów.Ścieżka byłaby do zwrotu samochodów
/cars?color=red,blue,green
lub/cars/search?color=red,blue,green
Parametry na ścieżce są trudniejsze do odczytania, ponieważ pary nazwa / wartość nie są odizolowane od reszty ścieżki, która nie jest parą nazwa / wartość.
Ostatni komentarz. Wolę
/garages/yyy/cars
(zawsze w liczbie mnogiej) niż/garage/yyy/cars
(być może literówka w oryginalnej odpowiedzi), ponieważ pozwala to uniknąć zmiany ścieżki między liczbą pojedynczą a liczbą mnogą. W przypadku słów z dodanym „s” zmiana nie jest taka zła, ale zmiana/person/yyy/friends
na/people/yyy
wydaje się niewygodna.źródło
Aby rozwinąć odpowiedź Petera - możesz sprawić, aby Search był zasobem najwyższej klasy:
Zasób wyszukiwania będzie zawierał pola koloru, modelu, statusu garażowanego itp. I może być określony w formacie XML, JSON lub innym formacie. Podobnie jak zasób Samochód i garaż, możesz ograniczyć dostęp do wyszukiwań na podstawie uwierzytelnienia. Użytkownicy, którzy często uruchamiają te same wyszukiwania, mogą przechowywać je w swoich profilach, aby nie trzeba było ich ponownie tworzyć. Adresy URL będą na tyle krótkie, że w wielu przypadkach można je łatwo handlować za pośrednictwem poczty elektronicznej. Te przechowywane wyszukiwania mogą być podstawą niestandardowych kanałów RSS i tak dalej.
Istnieje wiele możliwości korzystania z Wyszukiwań, gdy myślisz o nich jako o zasobach.
Pomysł został wyjaśniony bardziej szczegółowo w tym Railscast .
źródło
Odpowiedź Justina jest prawdopodobnie właściwą drogą, chociaż w niektórych aplikacjach sensowne może być rozważenie konkretnego wyszukiwania jako zasobu jako takiego, na przykład jeśli chcesz obsługiwać nazwane zapisane wyszukiwania:
lub
źródło
Używam dwóch podejść do realizacji wyszukiwania.
1) Najprostszy przypadek - zapytanie powiązanych elementów i nawigacja.
Oznacza to zapytanie samochodów, które mają identyfikator garażu równy 1.
Możliwe jest również tworzenie bardziej złożonych wyszukiwań:
Samochody we wszystkich garażach w FirstStreet, które nie są czerwone (3. strona, 100 elementów na stronie).
2) Złożone zapytania są uważane za zwykłe zasoby, które są tworzone i można je odzyskać.
Treść POST do tworzenia wyszukiwania jest następująca:
Opiera się na Grails (kryteria DSL): http://grails.org/doc/2.4.3/ref/Domain%20Classes/createCriteria.html
źródło
To nie jest REST. Nie można zdefiniować identyfikatorów URI dla zasobów w interfejsie API. Nawigacja po zasobach musi być sterowana hipertekstem. W porządku, jeśli chcesz ładnych identyfikatorów URI i dużych ilości sprzężeń, ale nie nazywaj go REST, ponieważ bezpośrednio narusza ograniczenia architektury RESTful.
Zobacz ten artykuł twórcy REST.
źródło
Chociaż podoba mi się odpowiedź Justina, uważam, że dokładniej reprezentuje ona filtr, a nie wyszukiwanie. Co jeśli chcę wiedzieć o samochodach o nazwach rozpoczynających się od kamery?
Z mojego punktu widzenia możesz go wbudować w sposób, w jaki obsługujesz określone zasoby:
/ cars / cam *
Lub możesz po prostu dodać go do filtra:
/ cars / doors / 4 / name / cam * / colors / red, niebieski, zielony
Osobiście wolę ten drugi, jednak w żadnym wypadku nie jestem ekspertem od REST (pierwszy raz słyszałem o nim zaledwie 2 tygodnie temu ...)
źródło
/cars?name=cam*
RESTful nie zaleca używania czasowników w adresach URL / samochody / wyszukiwanie nie jest spokojny. Właściwym sposobem filtrowania / wyszukiwania / paginacji interfejsu API jest skorzystanie z parametrów zapytania. Mogą jednak zdarzyć się przypadki, gdy będziesz musiał złamać normę. Na przykład, jeśli przeszukujesz wiele zasobów, musisz użyć czegoś takiego jak / search? Q = zapytanie
Możesz przejść przez http://saipraveenblog.wordpress.com/2014/09/29/rest-api-best-practices/, aby poznać najlepsze praktyki projektowania RESTful API
źródło
Ponadto sugerowałbym również:
Tutaj
Search
jest uważany za podrzędny zasóbCars
zasobu.źródło
Tutaj jest wiele dobrych opcji dla twojego przypadku. Nadal powinieneś rozważyć użycie ciała POST.
Ciąg zapytania jest idealny dla twojego przykładu, ale jeśli masz coś bardziej skomplikowanego, np. Dowolną długą listę elementów lub logiczne warunki, możesz zdefiniować post jako dokument, który klient wysyła za pomocą POST.
Pozwala to na bardziej elastyczny opis wyszukiwania, a także pozwala uniknąć limitu długości adresu URL serwera.
źródło
Moja rada będzie następująca:
Edytować:
Mam nadzieję, że to daje ci pomysł. Zasadniczo Twój interfejs API Rest powinien być łatwo wykrywalny i powinien umożliwiać przeglądanie danych. Kolejną zaletą korzystania z adresów URL, a nie ciągów zapytań, jest możliwość korzystania z natywnych mechanizmów buforowania istniejących na serwerze WWW dla ruchu HTTP.
Oto link do strony opisującej zło łańcuchów zapytań w REST: http://web.archive.org/web/20070815111413/http://rest.blueoxen.net/cgi-bin/wiki.pl?QueryStringsConsoveredHarmful
Użyłem pamięci podręcznej Google, ponieważ normalna strona nie działała dla mnie, oto również ten link: http://rest.blueoxen.net/cgi-bin/wiki.pl?QueryStringsConsoveredHarmful
źródło
/cars/colors/red,blue,green
i/cars/colors/green,blue,red
? Element ścieżki identyfikatora URI powinien być hierarchiczny i nie wydaje mi się, żeby tak było w tym przypadku. Myślę, że jest to sytuacja, w której ciąg zapytania jest najbardziej odpowiednim wyborem.