Chcę, aby mój interfejs API RESTful był bardzo przewidywalny. Jaka jest najlepsza praktyka przy podejmowaniu decyzji, kiedy dokonać segmentacji danych przy użyciu identyfikatora URI, a nie przy użyciu parametrów zapytania.
Wydaje mi się sensowne, że parametry systemowe obsługujące paginację, sortowanie i grupowanie znajdują się po znaku „?” A co z polami takimi jak „stan” i „region” lub innymi atrybutami, które dzielą Twoją kolekcję na segmenty? Jeśli mają to być również parametry zapytania, jaka jest praktyczna zasada dotycząca tego, kiedy należy używać parametrów ścieżki?
Odpowiedzi:
Najlepszą praktyką w projektowaniu interfejsu API zgodnego z REST jest to, że parametry ścieżki są używane do identyfikowania określonego zasobu lub zasobów, a parametry zapytania są używane do sortowania / filtrowania tych zasobów.
Oto przykład. Załóżmy, że implementujesz punkty końcowe interfejsu API RESTful dla jednostki o nazwie Car. Skonstruowałbyś swoje punkty końcowe w następujący sposób:
GET
/cars
GET
/cars/:id
POST
/cars
PUT
/cars/:id
DELETE
/cars/:id
W ten sposób parametry ścieżki są używane tylko podczas określania zasobu do pobrania, ale w żaden sposób nie sortuje / filtruje zasobów.
Załóżmy teraz, że chcesz dodać możliwość filtrowania samochodów według koloru w żądaniach GET. Ponieważ kolor nie jest zasobem (jest właściwością zasobu), można dodać parametr zapytania, który to robi. Dodałbyś ten parametr zapytania do żądania GET w
/cars
następujący sposób:DOSTAĆ
/cars?color=blue
Ten punkt końcowy zostałby zaimplementowany, aby zwracane były tylko niebieskie samochody.
Jeśli chodzi o składnię, nazwy adresów URL powinny być pisane małymi literami. Jeśli masz nazwę jednostki, która zazwyczaj składa się z dwóch słów w języku angielskim, do oddzielenia słów należy użyć łącznika, a nie wielkości wielbłąda.
Dawny.
/two-words
źródło
Podstawowy sposób myślenia na ten temat jest następujący:
URI to identyfikator zasobu, który jednoznacznie identyfikuje określone wystąpienie TYPU zasobu. Jak wszystko inne w życiu, każdy obiekt (który jest instancją pewnego typu) ma zestaw atrybutów, które są albo niezmienne w czasie, albo czasowe.
W powyższym przykładzie samochód jest bardzo namacalnym przedmiotem, który ma takie atrybuty, jak marka, model i VIN - które nigdy się nie zmieniają, a kolor, zawieszenie itp. Mogą się zmieniać w czasie. Więc jeśli zakodujemy URI z atrybutami, które mogą się zmieniać w czasie (czasowo), możemy skończyć z wieloma identyfikatorami URI dla tego samego obiektu:
A po latach, jeśli kolor tego samego samochodu zmieni się na czarny:
Zwróć uwagę, że sama instancja samochodu (obiekt) nie uległa zmianie - zmienił się tylko kolor. Posiadanie wielu identyfikatorów URI wskazujących na tę samą instancję obiektu zmusi Cię do utworzenia wielu programów obsługi URI - nie jest to efektywny projekt i oczywiście nie jest intuicyjny.
Dlatego identyfikator URI powinien składać się tylko z części, które nigdy się nie zmienią i będą nadal jednoznacznie identyfikować ten zasób przez cały okres jego istnienia. Wszystko, co może się zmienić, powinno być zarezerwowane dla parametrów zapytania, takich jak:
Konkluzja - pomyśl o polimorfizmie.
źródło
W REST API nie powinieneś zbytnio przejmować się przewidywalnymi identyfikatorami URI. Już sama sugestia dotycząca przewidywalności URI odnosi się do niezrozumienia architektury RESTful. Zakłada, że klient powinien sam konstruować identyfikatory URI, czego naprawdę nie powinien.
Zakładam jednak, że nie tworzysz prawdziwego REST API, ale API „inspirowane REST” (takie jak Google Drive). W takich przypadkach ogólną zasadą jest „parametry ścieżki = identyfikacja zasobu” i „parametry zapytania = sortowanie zasobów”. Pojawia się więc pytanie, czy możesz jednoznacznie zidentyfikować swój zasób BEZ statusu / regionu? Jeśli tak, to być może jest to parametr zapytania. Jeśli nie, to jest to parametr ścieżki.
HTH.
źródło
Kiedyś zaprojektowałem API, którym był główny zasób
people
. Zwykle użytkownicy prosili o filtrowanie,people
więc aby uniemożliwić użytkownikom wywoływanie czegoś takiego za/people?settlement=urban
każdym razem, zaimplementowałem,/people/urban
co później umożliwiło mi łatwe dodawanie/people/rural
. Pozwala to również na dostęp do pełnej/people
listy, jeśli będzie to przydatne później. Krótko mówiąc, moim rozumowaniem było dodanie ścieżki do wspólnych podzbiorówOd tutaj :
źródło
Ogólnie rzecz biorąc, zwykle używam parametrów ścieżki, gdy w zasobie istnieje oczywista „hierarchia”, na przykład:
Jeśli ten pojedynczy zasób ma status, można:
Jeśli jednak „region” nie jest tak naprawdę częścią udostępnianego zasobu, prawdopodobnie należy do jednego z parametrów zapytania - podobnie jak w przypadku paginacji (jak wspomniałeś).
źródło
Segmentacja jest bardziej hierarchiczna i „ładna”, ale może być ograniczająca.
Na przykład, jeśli masz adres URL z trzema segmentami, z których każdy przekazuje inne parametry wyszukiwania samochodu według marki, modelu i koloru:
Jest to bardzo ładny adres URL i łatwiejszy do zapamiętania przez użytkownika końcowego, ale teraz utknąłeś w tej strukturze. Powiedzmy, że chcesz, aby podczas wyszukiwania użytkownik mógł znaleźć WSZYSTKIE niebieskie samochody lub WSZYSTKIE samochody Honda Civics? Parametr zapytania rozwiązuje ten problem, ponieważ podaje parę klucz-wartość. Więc możesz przejść:
Teraz masz sposób na odwołanie się do wartości za pomocą jej klucza - „kolor” lub „marka” w kodzie zapytania.
Możesz obejść ten problem, używając większej liczby segmentów, aby stworzyć rodzaj struktury kluczowej wartości, takiej jak:
Mam nadzieję, że to ma sens ...
źródło
Przykładowy adres URL:
/rest/{keyword}
Ten adres URL jest przykładem parametrów ścieżki. Możemy uzyskać te dane URL za pomocą
@PathParam
.Przykładowy adres URL:
/rest?keyword=java&limit=10
Ten adres URL jest przykładem parametrów zapytania. Możemy uzyskać te dane URL za pomocą
@Queryparam
.źródło