REST, HTTP DELETE i parametry

135

Czy jest coś innego niż REST w podawaniu parametrów w żądaniu HTTP DELETE?


Mój scenariusz jest taki, że modeluję „Czy na pewno chcesz to usunąć?” scenariusz. W niektórych przypadkach stan zasobu sugeruje, że żądane usunięcie może być nieprawidłowe. Prawdopodobnie możesz sobie wyobrazić scenariusze, w których wymagane jest potwierdzenie usunięcia

Rozwiązaniem, które przyjęliśmy, jest przekazanie parametru do żądania usunięcia, aby wskazać, że można kontynuować usuwanie („? Force_delete = true”)

na przykład

DELETE http://server/resource/id?force_delete=true

Uważam, że od:

(a) Semantyka DELETE nie jest zmieniana - użytkownik nadal może wysłać normalne żądanie DELETE, ale może się to nie udać z 409, a treść odpowiedzi wyjaśni dlaczego. Mówię, że może się nie powieść, ponieważ (z powodów nie wartych wyjaśnienia) w niektórych przypadkach nie ma powodu, aby monitować użytkownika.

(b) W rozprawie Roya nic nie sugeruje, że jest to sprzeczne z duchem REST - dlaczego miałoby istnieć, skoro HTTP jest tylko jedną implementacją REST, więc dlaczego przekazywanie parametrów HTTP ma znaczenie


Czy ktoś może wskazać mi ostateczne stwierdzenie, które wyjaśnia powód, dla którego nie jest to RESTful?

W przypadku pokrewnego pytania, jeśli użytkownik nie określi force_delete, to zwracam 409 Conflict- czy to jest najbardziej odpowiedni kod odpowiedzi?


Zagryźć

Po dalszych badaniach myślę, że dodanie parametrów do DELETE może naruszyć kilka zasad.

Po pierwsze, implementacja prawdopodobnie narusza „Uniform Interface” (patrz sekcja 5.1.5 rozprawy Roya

Dodając „force_delete” dodajemy dodatkowe ograniczenie do już dobrze zdefiniowanej metody DELETE. To ograniczenie ma znaczenie tylko dla nas.

Można również argumentować, że narusza to „5.1.2 klient-serwer”, ponieważ okno dialogowe potwierdzenia dotyczy naprawdę interfejsu użytkownika i znowu nie wszyscy klienci będą chcieli potwierdzić usunięcie.

Sugestie ktoś?

Chris McCauley
źródło
1
Twój adres URL rozprawy Roya zawiera znak „)”, który powoduje, że 404. ics.uci.edu/~fielding/pubs/dissertation/rest_arch_style.htm działa.
NuclearPeon

Odpowiedzi:

78

Nie, to nie jest RESTful. Jedynym powodem, dla którego powinieneś umieszczać czasownik ( force_delete) w identyfikatorze URI, jest przeciążenie metod GET / POST w środowisku, w którym metody PUT / DELETE nie są dostępne. Sądząc po zastosowaniu metody DELETE, tak nie jest.

Kod błędu HTTP 409/Conflictpowinien być używany w sytuacjach, w których występuje konflikt uniemożliwiający usłudze RESTful wykonanie operacji, ale nadal istnieje szansa, że ​​użytkownik sam będzie mógł rozwiązać konflikt. Potwierdzenie przed usunięciem (gdzie nie ma rzeczywistych konfliktów, które uniemożliwiłyby usunięcie) nie jest konfliktem per se, ponieważ nic nie stoi na przeszkodzie, aby API wykonało żądaną operację.

Jak powiedział Alex (nie wiem, kto go przegłosował, ma rację), powinno się to załatwić w interfejsie użytkownika, ponieważ usługa RESTful jako taka tylko przetwarza żądania i dlatego powinna być bezpaństwowa (tj. Nie może polegać na potwierdzeniach przez przytrzymanie wszelkie informacje po stronie serwera dotyczące żądania).

Oto dwa przykłady, jak to zrobić w interfejsie użytkownika:

  • pre-HTML5 : * pokaż użytkownikowi okno dialogowe potwierdzenia JS i wyślij żądanie tylko wtedy, gdy użytkownik je potwierdzi
  • HTML5 : * użyj formularza z akcją DELETE, gdzie formularz będzie zawierał tylko przyciski „Potwierdź” i „Anuluj” („Potwierdź” byłby przyciskiem przesyłania)

(*) Należy pamiętać, że wersje HTML wcześniejsze niż 5 nie obsługują natywnie metod PUT i DELETE HTTP, jednak większość nowoczesnych przeglądarek może wykonywać te dwie metody za pośrednictwem wywołań AJAX. Zobacz ten wątek, aby uzyskać szczegółowe informacje na temat obsługi różnych przeglądarek.


Aktualizacja (na podstawie dodatkowego dochodzenia i dyskusji):

Scenariusz, w którym usługa wymagałaby force_delete=trueobecności flagi, narusza jednolity interfejs zdefiniowany w rozprawie Roya Fieldinga. Ponadto, zgodnie z protokołem HTTP RFC , metoda DELETE może zostać zastąpiona na serwerze pochodzenia (kliencie), co oznacza, że ​​nie jest to wykonywane na serwerze docelowym (usłudze).

Więc gdy usługa otrzyma żądanie DELETE, powinna je przetworzyć bez konieczności dodatkowego potwierdzenia (niezależnie od tego, czy usługa faktycznie wykonuje operację).

MicE
źródło
2
Czy możesz wyjaśnić, które ograniczenie REST jest naruszane? Biorąc pod uwagę, że identyfikatory URI powinny być nieprzejrzyste dla klienta, dlaczego uważasz, że oczekiwania klienta nie są spełniane przy użyciu funkcji HTTP DELETE, która usuwa jeden zasób, ale nie usuwa innego. Nie jestem pewien, czy 409 to najlepszy kod stanu do zwrócenia, ale poza tym, że jest trochę dziwną implementacją, nie mogę znaleźć żadnych ograniczeń REST, które są zepsute.
Darrel Miller
2
@Darrel: (imho) narusza jednolity interfejs przez metodę DELETE, która nie działa zgodnie ze standardami HTTP. Rozważmy klienta REST, który zakłada standardową usługę REST - w jaki sposób usługa poinformuje klienta, że ​​musi dodać force_delete=true? Zgodnie z protokołem HTTP RFC metoda DELETE może zostać zastąpiona na serwerze pochodzenia (kliencie), co oznacza, że ​​nie jest to wykonywane na serwerze docelowym (usłudze). Rozumiem więc, że gdy usługa otrzyma żądanie DELETE, powinna je przetworzyć bez potrzeby żadnego potwierdzenia (niezależnie od tego, czy usługa faktycznie wykonuje operację).
MicE
1
@ Chris, do drugiej kwestii: tak, to też rozumiem, tj. Państwo sugeruje prawdziwy konflikt, a nie potrzebę potwierdzenia. Właśnie zauważyłem aktualizację, którą zrobiłeś w swoim pytaniu i zgadzam się - podczas gdy ja sam się tym przyglądałem, doszedłem do tego samego wniosku (że narusza to jednolity interfejs, a potwierdzenie należy zrobić w kliencie / UI bok). Natknąłem się również na bardzo interesujący wątek, który może pomóc: mail-archive.com/[email protected]/msg13578.html
MicE
2
@MicE W dużej mierze zgadzam się z Tobą, że nie jest to idealny sposób na poradzenie sobie z takim scenariuszem. Jestem trochę wybredny, jeśli chodzi o etykietę „to nie jest RESTful”. Przez chwilę tutaj to zdanie zostało rzucone na wszystko. Jednak byłoby możliwe zdefiniowanie reguł dla typu mediów, które mówią, że jeśli spróbujesz USUNĄĆ zasób i pojawi się błąd (powiedziałbym, że 403 zabronione byłoby lepsze niż 409), wtedy klient powinien spróbować USUNĄĆ na pokrewnym zasobie przyczepiając się do „force_delete = true”. W pewnym sensie przypomina to autoryzację. Wykonaj GET, pobierz 401, dodaj nagłówek auth i ponownie GET.
Darrel Miller,
2
@Darrel: to bardzo dobra uwaga, dziękuję. I widziałem, jak ludzie sami nadawali etykietę nie RESTful . Może się zdarzyć, że w dzisiejszych czasach bariera między usługami a aplikacjami internetowymi staje się bardzo mglista, więc jeden zestaw ludzi może to zobaczyć z punktu widzenia czystej usługi, podczas gdy inni widzą to z mieszanego punktu widzenia aplikacji / usługi. To jest moim zdaniem, w którym pojawia się prawdziwe pytanie, jak dokonać bierzmowania. @Chris: zaktualizowane - dziękuję panu za bardzo ciekawy temat i dyskusję!
MicE
35

Myślę, że to nie jest uspokajające. Nie sądzę, aby uspokajająca usługa spełniała wymóg zmuszania użytkownika do potwierdzenia usunięcia. Poradziłbym sobie z tym w interfejsie użytkownika.

Czy określenie force_delete = true ma sens, jeśli jest to interfejs API programu? Jeśli ktoś pisał skrypt usuwający ten zasób, czy chciałbyś zmusić go do określenia force_delete = true, aby faktycznie usunąć zasób?

Alex Rockwell
źródło
Pierwszy akapit twojej odpowiedzi jest twoją opinią i szanuję ją, ale nie wskazałeś na coś w literaturze, co zabrania używania URI takiego jak ten - wciąż identyfikuje zasób i jest używany najbardziej odpowiedni czasownik HTTP. W odpowiedzi na Twoje pytania; tak, to nadal miałoby sens (moim zdaniem). Spodziewałbym się, że skrypt (być może oparty na CURL) uszanuje odpowiedź 409 i zasugeruje użytkownikowi, w jaki sposób żądanie może zostać ponownie wysłane - wszystko w oparciu o treść mojej odpowiedzi
Chris McCauley
Dobra uwaga na temat porównania internetowego interfejsu API z interfejsem API programu. To często dobry sposób, aby dowiedzieć się, czy interfejs API jest zgodny z REST, czy nie.
laurent
18

To stare pytanie, ale oto kilka komentarzy ...

  1. W SQL, polecenie DELETE akceptuje parametr „CASCADE”, który pozwala określić, że obiekty zależne również powinny zostać usunięte. To jest przykład parametru DELETE, który ma sens, ale „man rm” może dostarczyć inne. Jak te przypadki mogłyby zostać zaimplementowane w REST / HTTP bez parametru?
  2. @Jan, wydaje się, że ugruntowaną konwencją jest to, że część adresu URL będąca ścieżką identyfikuje zasób, podczas gdy kwerenda nie (przynajmniej niekoniecznie). Mnóstwo przykładów: uzyskiwanie tego samego zasobu, ale w innym formacie, uzyskiwanie określonych pól zasobu itp. Jeśli weźmiemy pod uwagę kwerendę jako część identyfikatora zasobu, nie można mieć pojęcia „różne widoki tego samego zasobu” bez korzystania z mechanizmów nieobsługujących REST, takich jak negocjacja zawartości HTTP (co może być niepożądane z wielu powodów).
Shay Rojansky
źródło
Dzięki za dodanie tego do rozmowy, nawet jeśli nie jest to rozmowa, ponieważ trwa latami.
silviot
6

Oprócz odpowiedzi Alexa:

Zauważ, że http: // server / resource / id? Force_delete = true identyfikuje inny zasób niż http: // server / resource / id. Na przykład ogromna różnica polega na tym, czy usuniesz / customers /? Status = old czy / customers /.

Jan Algermissen
źródło
Nie zgadzam się, mogę podać wiele identyfikatorów URI w celu identyfikacji tego samego zasobu.
Chris McCauley,
19
Tak - każdy może narobić bałaganu :-)
Jan Algermissen
Może w tym pomóc wskazanie kanonicznych identyfikatorów URI: googlewebmastercentral.blogspot.com/2009/02/…
MicE
@Chris Powinien istnieć tylko jeden identyfikator URI, który zwraca reprezentację zasobu. Inne identyfikatory URI mogą odnosić się do tej samej koncepcji, ale wykonanie GET powinno zwrócić 303 Zobacz inne. Aby przeciwdziałać oczywistemu zarzutowi, /foo.xml i /foo.json to dwa różne zasoby.
Darrel Miller,
@Darrell - zgadzam się, ale format nie jest tutaj problemem. Również .format jest konwencją w Railsach i innych frameworkach, która nie jest częścią REST - aby w pełni to zaimplementować, powinieneś używać negocjacji treści w HTTP z MIME lub mikroformatami.
Chris McCauley