O ile mogę stwierdzić, każdy pojedynczy zasób powinien mieć tylko jedną ścieżkę kanoniczną . Więc w poniższym przykładzie, jakie byłyby dobre wzorce adresów URL?
Weźmy na przykład reprezentację firm. W tym hipotetycznym przykładzie każda firma posiada 0 lub więcej działów, a każdy dział posiada 0 lub więcej pracowników.
Dział nie może istnieć bez powiązanej firmy.
Pracownik nie może istnieć bez powiązanego działu.
Teraz znajdę naturalną reprezentację wzorców zasobów.
/companies
Zbiór firm - Akceptuje dla nowej firmy. Zdobądź całą kolekcję./companies/{companyId}
Indywidualna firma. Akceptuje GET, PUT i DELETE/companies/{companyId}/departments
Akceptuje POST dla nowego przedmiotu. (Tworzy dział w firmie)./companies/{companyId}/departments/{departmentId}/
/companies/{companyId}/departments/{departmentId}/employees
/companies/{companyId}/departments/{departmentId}/employees/{empId}
Biorąc pod uwagę ograniczenia, w każdej sekcji uważam, że ma to sens, jeśli jest nieco zagnieżdżone.
Jednak moja trudność pojawia się, gdy chcę wymienić ( GET
) wszystkich pracowników we wszystkich firmach.
Wzorzec zasobów dla tego byłby najbardziej zbliżony do /employees
(Zbiór wszystkich pracowników)
Czy to oznacza, że powinienem /employees/{empId}
również mieć, ponieważ jeśli tak, to istnieją dwa identyfikatory URI, aby uzyskać ten sam zasób?
A może cały schemat powinien zostać spłaszczony, ale oznaczałoby to, że pracownicy są zagnieżdżonymi obiektami najwyższego poziomu.
Na poziomie podstawowym /employees/?company={companyId}&department={deptId}
zwraca dokładnie ten sam widok pracowników, co najgłębiej zagnieżdżony wzór.
Jaka jest najlepsza praktyka w zakresie wzorców adresów URL, w których zasoby są własnością innych zasobów, ale powinny być dostępne osobne zapytania?
źródło
Odpowiedzi:
To, co zrobiłeś, jest poprawne. Zasadniczo do tego samego zasobu może być wiele identyfikatorów URI - nie ma reguł, które mówią, że nie powinieneś tego robić.
Ogólnie rzecz biorąc, być może będziesz musiał uzyskać dostęp do elementów bezpośrednio lub jako podzbiór czegoś innego - więc twoja struktura ma dla mnie sens.
Tylko dlatego, że pracownicy są dostępni w dziale:
company/{companyid}/department/{departmentid}/employees
Nie oznacza to, że nie mogą być również dostępne w firmie:
company/{companyid}/employees
Co zwróci pracowników dla tej firmy. Zależy to od tego, czego potrzebuje Twój konsumujący klient - do tego właśnie powinieneś projektować.
Mam jednak nadzieję, że wszystkie procedury obsługi adresów URL używają tego samego kodu zabezpieczającego do zaspokojenia żądań, aby nie powielać kodu.
źródło
/company/3/department/2/employees/1
). Jeśli interfejs API zapewnia sposoby uzyskania każdego zasobu, wówczas każde z tych żądań można wykonać w bibliotece po stronie klienta lub jako jednorazowy punkt końcowy, który ponownie wykorzystuje kod./company/*
powinien zwracać tylko zasób firmy i w ogóle nie zmieniać typu zasobu. Żadna z tych informacji nie jest określona przez REST - jest to ogólnie słabo określona - tylko osobiste preferencje.Wypróbowałem obie strategie projektowania - zagnieżdżone i nie zagnieżdżone punkty końcowe. Znalazłem to:
jeśli zagnieżdżony zasób ma klucz podstawowy, a nie masz jego nadrzędnego klucza podstawowego, struktura zagnieżdżona wymaga jego uzyskania, nawet jeśli system go nie wymaga.
zagnieżdżone punkty końcowe zwykle wymagają redundantnych punktów końcowych. Innymi słowy, będziesz potrzebować dodatkowego punktu końcowego / pracowników, aby uzyskać listę pracowników z różnych działów. Jeśli masz / pracowników, co dokładnie kupują / firmy / działy / pracownicy?
zagnieżdżanie punktów końcowych nie rozwija się tak ładnie. Np. Być może nie będziesz musiał szukać pracowników teraz, ale możesz później, a jeśli masz zagnieżdżoną strukturę, nie masz innego wyboru, jak dodać kolejny punkt końcowy. W przypadku projektu zagnieżdżonego wystarczy dodać więcej parametrów, co jest prostsze.
czasami zasób może mieć wiele rodzajów rodziców. W rezultacie powstaje wiele punktów końcowych, wszystkie zwracają ten sam zasób.
redundantne punkty końcowe utrudniają pisanie dokumentów, a także utrudniają naukę interfejsu API.
Krótko mówiąc, wydaje się, że nie zagnieżdżony projekt pozwala na bardziej elastyczny i prostszy schemat punktu końcowego.
źródło
Przesunąłem to, co zrobiłem, z pytania do odpowiedzi, w której prawdopodobnie więcej osób je zobaczy.
To, co zrobiłem, to mieć punkty końcowe tworzenia w zagnieżdżonym punkcie końcowym. Kanoniczny punkt końcowy do modyfikowania lub odpytywania elementu nie znajduje się w zagnieżdżonym zasobie .
Tak więc w tym przykładzie (wystarczy wymienić punkty końcowe, które zmieniają zasób)
POST
/companies/
tworzy nową firmę zwraca link do utworzonej firmy.POST
/companies/{companyId}/departments
po umieszczeniu działu tworzy nowy dział zwraca link do/departments/{departmentId}
PUT
/departments/{departmentId}
modyfikuje działPOST
/departments/{deparmentId}/employees
tworzy nowy pracownik zwraca link do/employees/{employeeId}
Istnieją więc zasoby na poziomie głównym dla każdej kolekcji. Jednak tworzenie odbywa się w obiekcie będącym właścicielem .
źródło
POST
znaczeniaPUT
, i inaczej.Przeczytałem wszystkie powyższe odpowiedzi, ale wygląda na to, że nie mają wspólnej strategii. Znalazłem dobry artykuł na temat najlepszych praktyk w API Design z Microsoft Documents . Myślę, że powinieneś polecić.
.
źródło
Wygląd adresów URL nie ma nic wspólnego z usługą REST. Wszystko idzie. W rzeczywistości jest to „szczegół implementacji”. Więc tak jak nazywasz swoje zmienne. Muszą być jedyne w swoim rodzaju i trwałe.
Nie marnuj na to zbyt wiele czasu, po prostu dokonaj wyboru i trzymaj się go / bądź konsekwentny. Na przykład, jeśli korzystasz z hierarchii, robisz to dla wszystkich swoich zasobów. Jeśli korzystasz z parametrów zapytań ... itd., Podobnie jak konwencje nazewnictwa w kodzie.
Dlaczego tak ? O ile mi wiadomo, API „RESTful” ma być możliwe do przeglądania (wiesz… „Hypermedia jako silnik stanu aplikacji”), dlatego klient API nie dba o to, jakie są twoje adresy URL, o ile są ważne (nie ma SEO, żaden człowiek nie musiałby czytać tych „przyjaznych adresów URL”, z wyjątkiem tego, że może służyć do debugowania ...)
To, jak ładny / zrozumiały jest adres URL w interfejsie API REST, jest interesujące tylko dla programisty interfejsu API, a nie dla klienta interfejsu API, tak jak nazwa zmiennej w kodzie.
Najważniejsze jest to, że klient interfejsu API wie, jak interpretować typ multimediów. Na przykład wie, że:
Poniżej znajduje się przykładowa wymiana HTTP (ciała są w yaml, ponieważ łatwiej jest pisać):
Żądanie
Odpowiedź: lista linków do głównego zasobu (firmy, ludzie, cokolwiek ...)
Żądanie: link do firm (przy użyciu body.links.companies poprzedniej odpowiedzi)
Odpowiedź: częściowa lista firm (poniżej pozycji), zasób zawiera powiązane linki, takie jak link do uzyskania następnych kilku firm (body.links.next) inny (szablonowy) link do wyszukiwania (body.links.search)
Tak więc, jak widzisz, jeśli korzystasz z linków / relacji, sposób, w jaki tworzysz ścieżkę, część twoich adresów URL nie ma żadnej wartości dla twojego klienta API. A jeśli komunikujesz strukturę swoich adresów URL swojemu klientowi jako dokumentację, to nie robisz REST (lub przynajmniej nie Poziom 3 zgodnie z „ modelem dojrzałości Richardsona ”)
źródło
Nie zgadzam się z tego rodzaju ścieżką
Jeśli chcesz dostać działy, myślę, że lepiej jest użyć zasobu / departments
Przypuszczam, że masz
companies
tabelę idepartments
tabelę, a następnie klasy, aby zmapować je w używanym języku programowania. Zakładam również, że działy mogą być przyłączone do innych podmiotów niż firmy, więc zasób / działy jest prosty, wygodnie jest mieć zasoby odwzorowane na tabele, a także nie potrzebujesz tylu punktów końcowych, ponieważ możesz ponownie użyćna przykład do dowolnego wyszukiwania
Jeśli chcesz utworzyć dział,
należy użyć zasobu, a treść żądania powinna zawierać identyfikator firmy (jeśli dział można powiązać tylko z jedną firmą).
źródło
GET /companies/{companyId}?include=departments
Ponieważ pozwala to na pobranie zarówno firmy, jak i jej działów w jednym żądaniu HTTP. Fractal robi to naprawdę dobrze./departments
punkt końcowy, aby był dostępny tylko dla administratora, i każda firma ma dostęp do swoich działów tylko przez `/ company / {companyId} / departments`Rails zapewnia rozwiązanie tego problemu: płytkie zagnieżdżanie .
Myślę, że jest to dobre, ponieważ w przypadku bezpośredniego kontaktu ze znanym zasobem nie ma potrzeby korzystania z zagnieżdżonych tras, co omówiono w innych odpowiedziach tutaj.
źródło