Końcowy ukośnik w RESTful API

60

Dyskutowałem o tym, co zrobić z końcowym ukośnikiem w interfejsie API RESTful.

Powiedzmy, że mam zasób zwany psami i zasoby podrzędne dla poszczególnych psów. Możemy zatem wykonać następujące czynności:

GET/PUT/POST/DELETE http://example.com/dogs
GET/PUT/POST/DELETE http://example.com/dogs/{id}

Ale co robimy w następującym specjalnym przypadku:

GET/PUT/POST/DELETE http://example.com/dogs/

Moim osobistym zdaniem jest to, że oznacza to wysłanie żądania do pojedynczego zasobu psa o id = null. Myślę, że interfejs API powinien zwrócić 404 dla tego przypadku.

Inni twierdzą, że żądanie dostępu do zasobu psów, tzn. Ukośnik końcowy jest ignorowany.

Czy ktoś zna ostateczną odpowiedź?

Gaz_Edge
źródło
2
Myślałem, że RESTful sposób polega na rozróżnieniu psa / identyfikatora i psów (czyli wszystkich psów).
pdr
Z książki RESTful Web Services - zasoby podrzędne: zasoby, które istnieją w odniesieniu do niektórych innych „nadrzędnych” zasobów, tj. Psów / {id} Baza danych z dostępem do Internetu może ujawniać tabelę jako zasób, a poszczególne wiersze bazy danych jako zasoby podrzędne .
Gaz_Edge
Uzyskuje dostęp do zasobu psa, ukośnik końcowy należy zignorować, co oznacza, że ​​powinien otrzymać zabronioną odpowiedź za próbę usunięcia czegoś, do czego nie należy go usuwać. Myślę, że 404 jest również do przyjęcia. Czy to ma znaczenie?
Benjamin Gruenbaum
Nie śledzę - kto powiedział, że nie możesz usuwać psów? Usunięcie psów powoduje usunięcie siebie i wszystkich pojedynczych psów. Dlatego myślę, że zezwalanie na połączenia z psami / jest ryzykowne. Co jeśli klient chciał usunąć pojedynczego psa, ale przypadkowo zostawił {id}. W rezultacie wszystkie psy zostaną usunięte. Znacznie bezpieczniej jest założyć, że prosi o {id} zerową wartość i zwraca 404
Gaz_Edge
Traktowałbym dogsi dogs/jako równoważny. Dla mnie jasne dogs/jest, że jest to katalog zawierający poszczególne psy. Jest mniej jasne, co dogsjest, ale traktowałbym to jako równoważne, tak jak większość serwerów akceptuje dostęp do katalogów bez końcowego /.
CodesInChaos

Odpowiedzi:

50

Nic z tego nie jest wiarygodne (ponieważ REST nie ma dokładnego znaczenia). Ale z oryginalnego artykułu na temat REST pełny (nie kończący się na /) adres URL nazywa zasób, podczas gdy jeden kończący się ukośnikiem „/” to grupa zasobów (prawdopodobnie nie tak sformułowana).

GET adresu URL z ukośnikiem na końcu powinien zawierać listę dostępnych zasobów.

GET http://example.com/dogs/          /* List all the dogs resources */

PUT na adres URL z ukośnikiem ma zastąpić wszystkie zasoby.

PUT http://example.com/dogs/          /* Replace all the dogs resources */

DELETE na adresie URL z ukośnikiem ma usunąć wszystkie zasoby

DELETE http://example.com/dogs/       /* Deletes all the dogs resources */

Następnie można uzyskać dostęp do POST na adresie URL z ukośnikiem, aby utworzyć nowy zasób. Aby zachować zgodność, nowy zasób powinien znajdować się w tym katalogu (chociaż wiele oszustw RESTful tutaj oszukuje).

POST http://example.com/dogs/        /* Creates a new dogs resource (notice singular) */

itp.

Strona wiki na ten temat wydaje się to dobrze wyjaśniać:

Zobacz przykład https://en.wikipedia.org/wiki/Representational_state_transfer#Applied_to_Web_services .

Martin York
źródło
Pasuje również do normalnego modelu ścieżki / /
adresu
4
Co więc powinno się stać, jeśli uzyskasz dostęp do grupy zasobów bez końcowego /?
oberlies
1
@oberlies: To zależy od kontekstu. Nie ma twardych i szybkich reguł, a tylko najlepsze praktyki. Zasada jest zawsze objaśniona i powinna oznaczać to, czego się spodziewasz. W powyższym przykładzie: GET http://example.com/dogsmoże zwracać meta informacje o psach (nie samą listę, ale meta informacje o liście psów). Może, a może to błąd.
Martin York,
1
As the last character within a URI’s path, a forward slash (/) adds no semantic value and may cause confusion. It’s better to drop them completely.To nie jedyne miejsce, które sugeruje, aby nie używać slash treningowy
Laiv
@Laiv Nie zgadzam się z sentymentem. Ale proszę połączyć bardziej wiarygodne odniesienie (to słaby link).
Martin York,
17
Does anyone know the definitive answer?

Nie ma takiego, ponieważ nie ma oficjalnego dokumentu, który jest wymagany, aby usługa mogła zostać uznana za RESTful.

To powiedziawszy, ze pozwolę na końcowe cięcie po prostu dla łatwości użycia. Technicznie rzecz biorąc, może to być postrzegane jako próba uzyskania dostępu do psa z zerowym identyfikatorem; Nie widzę, żeby użytkownik wykonywał ten skok, chyba że przeczytał go w twojej dokumentacji. Widzę, że użytkownik próbuje napisać kod przeciw Twojemu API i dołącza ukośnik po prostu z przyzwyczajenia i zastanawia się, dlaczego otrzyma odpowiedź 404, gdy chce listy psów.

Mikrofon
źródło
Co z DELETE example.com/dogs ?
Benjamin Gruenbaum,
ponieważ psy są rodzicami wszystkich pojedynczych psów, usunięcie psów usunie wszystkie pojedyncze psy i siebie. Jeśli tego nie zrobisz, twoja hipermedia się załamie
Gaz_Edge
@Gaz_Edge: W REST example.com/dogsjest zasób całkowicie niezależny od dowolnego zasobu example.com/dogs/X. Dlatego DELETE on example.com/dogsnie musi usuwać wszystkich psów / * (choć może, jeśli jest to semantyka). Ale DELETE example.com/dogs/powinno usunąć wszystkie psy / *.
Martin York
3
Chciałbym jeszcze raz powiedzieć, że skoro nie ma definitywnego zestawu reguł dotyczących tego, co jest RESTful, to co stanie się, gdy USUŃ / psy lub / psy / będzie oparte na tym, czego oczekujesz od konsumentów interfejsu API. Czy prawdopodobne jest, że faktycznie chcieliby usunąć wszystkie psy za pomocą jednego żądania? Jeśli tak, to zaimplementuj go w ten sposób, jeśli nie, podaj odpowiedź 405 Niedozwolona metoda.
Mike
1
Wiem, że to stary wątek, ale ostatnio sam się nad tym zastanawiałem. Na co warto, OS X traktuje powłoki bash foo, foo/i foo////identycznie. Zasadniczo wydaje się, że usuwa puste segmenty ścieżki. Jeśli więc zastosujesz to samo podejście do usługi REST dogsi dogs/odniesiesz się do tego samego.
Greg Brown,
2

Dwie drogi.

Metoda 1

Zawsze używaj końcowych ukośników dla każdego zasobu, który może zawierać dzieci.

Rozważ „GET” w katalogu public_html z plikami.

Nie jest możliwe, gdy plik hello.html jest plikiem:

/hello.html
/hello.html/youagain.html

Ale możliwe, gdy hello.html jest katalogiem:

/hello.html/     (actually /hello.html/index.html)
/hello.html/youagain.html

Jeśli więc „hello.html” może kiedykolwiek mieć dzieci, to zawsze jest to „/hello.html/” i „/hello.html/index.html” (lub po prostu /hello.html/) to lista tych dzieci .

Metoda 2

Bądź mądry".

$ find
.
./hello.html
./hello.html/index.html

Polecenie find nie przejmuje się typem hello.html. Katalog lub plik, kogo to obchodzi, to nazwa obiektu. Kiedy piszemy „cp youagain.html hello.html”, cp może dowiedzieć się, jak obsługiwać hello.html. cp jest mądry. Twój serwer również jest inteligentny. Ma bibliotekę do obsługi ścieżek. Ma routing. Może stat i powiedzieć, czy nazwa jest obiektem czy katalogiem. Może przekierowywać bla na bla / lub nawet po prostu podawać tę samą odpowiedź dla obu. To jest niesamowite !!! droga. Tyle techniki. Kto kiedykolwiek chciałby po prostu połączyć łańcuchy ścieżek, kiedy moglibyśmy to wszystko zrobić?

Samuel Danielson
źródło