Jakie są najlepsze praktyki dla zasobów zagnieżdżonych REST
O ile mogę powiedzieć, każdy pojedynczy zasób powinien mieć tylko jedną kanoniczną ścieżkę . Więc w poniższym przykładzie jakie byłyby dobre wzorce URL?
Weźmy na przykład reprezentację firm w stanie spoczynku. 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 exist bez powiązanego działu.
Teraz znajdowałbym naturalną reprezentację wzorców zasobów.
-
/companies
zbiór firm - przyjmuje put dla nowej firmy. Zdobądź całą kolekcję. -
/companies/{companyId}
indywidualna firma. Akceptuje GET, PUT I DELETE -
/companies/{companyId}/departments
akceptuje POST dla nowego artykułu. (Tworzy dział w ramach Towarzystwo.) /companies/{companyId}/departments/{departmentId}/
/companies/{companyId}/departments/{departmentId}/employees
/companies/{companyId}/departments/{departmentId}/employees/{empId}
Biorąc pod uwagę ograniczenia, w każdej z sekcji czuję, że ma to sens, jeśli jest trochę głęboko zagnieżdżone.
Jednak moja trudność przychodzi, jeśli chcę wymienić (GET
) wszystkich pracowników we wszystkich firmach.
Czy to znaczy, że powinienem mieć /employees/{empId}
również dlatego, że jeśli tak, to są dwa URI do uzyskać ten sam zasób?
A może cały schemat powinien zostać spłaszczony, ale oznaczałoby to, że pracownicy są zagnieżdżonym obiektem 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 dla wzorców URL, gdzie zasoby są własnością przez inne zasoby, ale powinny być dostępne osobno?
UPDATE: zobacz moją odpowiedź poniżej, aby zobaczyć, co mam załatwione.
6 answers
To, co zrobiłeś, jest poprawne. Ogólnie rzecz biorąc, może być wiele Uri do tego samego zasobu - nie ma zasad, które mówią, że nie powinieneś tego robić.
I ogólnie rzecz biorąc, możesz potrzebować dostępu 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 znaczy, że nie mogą być dostępne również pod firmą:
company/{companyid}/employees
Które zwracałyby pracowników za ta firma. To zależy od tego, czego potrzebuje twój konsumujący klient - do tego powinieneś projektować.
Ale mam nadzieję, że wszystkie programy obsługi adresów URL używają tego samego kodu pomocniczego, aby zaspokoić żądania, abyś nie powielał kodu.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-08-18 14:21:58
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 ty nie masz jego klucza nadrzędnego, zagnieżdżona struktura wymaga, aby go uzyskać, nawet jeśli system w rzeczywistości tego nie wymaga.
Zagnieżdżone punkty końcowe zazwyczaj wymagają zbędnych punktów końcowych. Innymi słowy, często będziesz potrzebować dodatkowego punktu końcowego / pracowników, aby uzyskać listę pracowników w różnych departamentach. Jeśli masz / pracowników, co dokładnie kupuje/firmy/działy / pracownicy?
Punkty końcowe zagnieżdżania nie ewoluują tak ładnie. Na przykład może nie trzeba szukać pracowników teraz, ale może później, a jeśli masz zagnieżdżoną strukturę, nie masz innego wyboru, jak dodać inny punkt końcowy. W przypadku projektu bez zagnieżdżenia wystarczy dodać więcej parametrów, co jest prostsze.
Czasami zasób może mieć wiele typów rodziców. W wyniku czego powstaje wiele wszystkie zwracają ten sam zasób.
Redundantne punkty końcowe utrudnia pisanie dokumentów, a także utrudnia naukę interfejsu api.
Krótko mówiąc, projekt bez zagnieżdżenia wydaje się pozwalać na bardziej elastyczny i prostszy schemat punktu końcowego.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-04-04 19:01:54
Przeniosłem to, co zrobiłem z Pytania do odpowiedzi, gdzie więcej osób może to zobaczyć.
To, co zrobiłem, to mieć punkty końcowe tworzenia w zagnieżdżonym punkcie końcowym, kanonicznym punktem końcowym modyfikacji lub zapytania elementu jest , a nie 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 utworzonego Towarzystwo. -
POST
/companies/{companyId}/departments
gdy dział zostanie utworzony, nowy dział zwróci link do/departments/{departmentId}
-
PUT
/departments/{departmentId}
modyfikuje dział -
POST
/departments/{deparmentId}/employees
utworzenie nowego pracownika zwraca link do/employees/{employeeId}
Więc istnieją zasoby na poziomie głównym dla każdej z kolekcji. Jednak create znajduje się w obiekcie posiadającym.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-08-29 12:11:44
Nie zgadzam się z tego rodzaju ścieżką
GET /companies/{companyId}/departments
Jeśli chcesz mieć działy, myślę, że lepiej jest użyć zasobu / działów
GET /departments?companyId=123
Przypuszczam, że masz companies
tabelę i departments
tabelę, a następnie klasy do mapowania ich w języku programowania, którego używasz. Zakładam również, że działy mogą być dołączone do innych podmiotów niż firmy, więc zasób a / departamentów jest prosty, wygodnie jest mieć zasoby mapowane do tabel, a także nie potrzebujesz tak wielu punktów końcowych ponieważ możesz ponownie użyć
GET /departments?companyId=123
Dla każdego rodzaju Wyszukiwania, na przykład
GET /departments?name=xxx
GET /departments?companyId=123&name=xxx
etc.
Jeśli chcesz utworzyć dział,
POST /departments
Należy użyć zasobu, a organ żądający powinien zawierać identyfikator firmy (jeśli dział może być połączony tylko z jedną firmą).
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-02-13 18:54:23
Wygląd adresów URL nie ma nic wspólnego z resztą. Wszystko idzie. W rzeczywistości jest to "szczegół realizacji". Tak jak nazywacie swoje zmienne. Wszystko, co musi być wyjątkowe i trwałe.
Nie trać na to zbyt wiele czasu, po prostu dokonaj wyboru i trzymaj się go / bądź konsekwentny. Na przykład, jeśli idziesz z hierarchiami, to robisz to dla wszystkich swoich zasobów. Jeśli wybierzesz parametry zapytania...itp. Podobnie jak konwencje nazewnictwa w Twoim kodzie. Dlaczego tak ? Z tego co wiem a "RESTful" API ma być przeglądane (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, nie ma człowieka, który musi czytać te "przyjazne adresy URL", z wyjątkiem może być do debugowania...)Jak ładny / zrozumiały jest adres URL w REST API jest interesujący tylko dla Ciebie jako programisty API, a nie klienta API, tak jak nazwa zmiennej w Twoim kodzie.
Najbardziej ważne jest to, że klient API wie, jak interpretować typ multimediów. Na przykład wie, że:
- Twój typ mediów ma właściwość linki, która wyświetla dostępne / powiązane linki.
- każdy link jest identyfikowany przez relację (tak jak przeglądarki wiedzą, że link[rel="arkusz stylów"] oznacza jego arkusz stylów lub rel=favico jest łączem do faviconu...)
- i wie, co oznaczają te relacje ("firmy" oznaczają listę firm, "Szukaj" oznacza szablon adresu URL do wyszukiwania na liście zasobów, "działy" oznacza działy bieżącego zasobu)
Poniżej znajduje się przykład wymiany HTTP (ciała są w yaml, ponieważ łatwiej jest pisać):
Request
GET / HTTP/1.1
Host: api.acme.io
Accept: text/yaml, text/acme-mediatype+yaml
Odpowiedź: lista linków do głównego zasobu (firmy, ludzie, cokolwiek...)
HTTP/1.1 200 OK
Date: Tue, 05 Apr 2016 15:04:00 GMT
Last-Modified: Tue, 05 Apr 2016 00:00:00 GMT
Content-Type: text/acme-mediatype+yaml
# body: this is your API's entrypoint (like a homepage)
links:
# could be some random path https://api.acme.local/modskmklmkdsml
# the only thing the API client cares about is the key (or rel) "companies"
companies: https://api.acme.local/companies
people: https://api.acme.local/people
Zapytanie: link do firm (z wykorzystaniem organu poprzedniej odpowiedzi.linki.firmy)
GET /companies HTTP/1.1
Host: api.acme.local
Accept: text/yaml, text/acme-mediatype+yaml
Odpowiedź: lista częściowa z firm (w pozycji), zasób zawiera powiązane linki, takie jak link, aby uzyskać następne kilka firm (ciało.linki.następny) inny (template) link do wyszukiwania (body.linki.Szukaj)
HTTP/1.1 200 OK
Date: Tue, 05 Apr 2016 15:06:00 GMT
Last-Modified: Tue, 05 Apr 2016 00:00:00 GMT
Content-Type: text/acme-mediatype+yaml
# body: representation of a list of companies
links:
# link to the next page
next: https://api.acme.local/companies?page=2
# templated link for search
search: https://api.acme.local/companies?query={query}
# you could provide available actions related to this resource
actions:
add:
href: https://api.acme.local/companies
method: POST
items:
- name: company1
links:
self: https://api.acme.local/companies/8er13eo
# and here is the link to departments
# again the client only cares about the key department
department: https://api.acme.local/companies/8er13eo/departments
- name: company2
links:
self: https://api.acme.local/companies/9r13d4l
# or could be in some other location !
department: https://api2.acme.local/departments?company=8er13eo
Więc jak widzisz, jeśli idziesz link / relacje sposób jak struktura część ścieżki adresów URL nie ma żadnej wartości dla klienta API. A jeśli przekazujesz strukturę swoich adresów URL Klientowi jako dokumentację, to nie odpoczywasz (lub przynajmniej nie Poziom 3 zgodnie z "model dojrzałości Richardsona")
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-08-26 16:11:00
Przeczytałem wszystkie powyższe odpowiedzi, ale wydaje się, że nie mają wspólnej strategii. Znalazłem dobry artykuł o najlepszych praktykach w projektowaniu API z Microsoft Documents . Myślę, że powinieneś się odnieść.
W bardziej złożonych systemach może być kuszące dostarczanie URI, które umożliwienie klientowi poruszania się po kilku poziomach relacji, takich jak
/customers/1/orders/99/products.
, jednak ten poziom złożoność może być trudna do utrzymania i jest nieelastyczna, jeśli relacje między zasobami zmieniają się w przyszłości. zamiast tego spróbuj zachowaj stosunkowo proste Uri. Gdy wniosek zawiera odniesienie do zasobów, powinno być możliwe użycie tego odniesienia do znalezienia przedmiotów związane z tym zasobem. Poprzedzające zapytanie można zastąpić URI/customers/1/orders
, aby znaleźć wszystkie zamówienia dla Klienta 1, oraz następnie/orders/99/products
, aby znaleźć produkty w tej kolejności.
.
Końcówka
Unikaj konieczności stosowania Uri zasobów bardziej złożonych niż
collection/item/collection
.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-06-19 02:25:36