2013-01-14 18 views
69

Podczas gdy HTTP 1.1 spec wydaje się zezwalać na żądania ciał na żądania , wydaje się, że serwery powinny go zignorować, ponieważ nie ma dla niego zdefiniowanej semantyki.RESTful Alternatywy dla żądania usunięcia ciała

4,3 Treść wiadomości

Serwer powinien przeczytać i przekazać wiadomość-ciało na każde żądanie; jeśli metoda żądania nie zawiera zdefiniowanej semantyki dla jednostki-podmiotu, , wówczas treść komunikatu POWINIEN być zignorowana podczas obsługi żądania.

Już przeglądowi kilka podobnych dyskusji na ten temat na SO i poza nią, takie jak:

Większość dyskusji wydają się zgadzają się, że podanie treści wiadomości na DELETE może być dozwolone , ale generalnie nie jest zalecane.

Co więcej, zauważyłem trend w różnych bibliotekach klientów HTTP, w których coraz więcej ulepszeń wydaje się być rejestrowanych dla tych bibliotek, aby obsługiwać ciałach żądań przy usuwaniu. Większość bibliotek wydaje się zobowiązywać, choć czasami z niewielkim początkowym oporem.

Mój przypadek użycia wymaga dodania niektórych wymaganych metadanych podczas operacji DELETE (np. "Przyczyna" usunięcia, a także kilka innych metadanych wymaganych do usunięcia). Mam rozważyć następujące opcje, z których żadna nie wydają się całkowicie właściwe i inline ze specyfikacją HTTP i/lub reszta najlepszych praktyk:

  • Treść wiadomości - Spec wskazuje, że treść wiadomości na DELETE nie mają wartości semantycznej; nie w pełni obsługiwany przez klientów HTTP; niestandardowa praktyka
  • Niestandardowe nagłówki HTTP - Wymaganie niestandardowych nagłówków jest zwykle następujące: against standard practices; ich używanie jest niezgodne z resztą mojego API, z których żaden nie wymaga niestandardowych nagłówków; Ponadto, nie jest dobre odpowiedzi HTTP dostępny do wskazania wartości nagłówków złe niestandardowych (prawdopodobnie osobną pytanie łącznie)
  • standardowe nagłówki HTTP - Brak standardowe nagłówki są odpowiednie
  • Parametry zapytania - tworzenie kwerendy params faktycznie zmienia się request- Identyfikator URI został usunięty; against standard practices
  • Metoda POST - (np. POST /resourceToDelete { deletemetadata }) POST nie jest opcją semantyczną do usuwania; POST faktycznie reprezentuje odwrotny działania pożądanego (tj POST tworzy podwładnych zasobów, ale muszę usunąć zasób)
  • wiele metod - podział żądanie DELETE na dwie operacje (np PUT usuwać metadane, a następnie usunąć) dzieli operacja atomowa na dwie, potencjalnie pozostawiając niespójny stan.Przyczyna usunięcia (i inne powiązane metadane) nie są częścią samej reprezentacji zasobów.

Moją pierwszą preferencją byłoby prawdopodobnie użycie treści wiadomości, a po drugie niestandardowe nagłówki HTTP; jednak, jak wskazano, istnieją pewne wady tych podejść.

Czy istnieją jakieś zalecenia lub najlepsze praktyki zgodne ze standardami REST/HTTP dotyczące uwzględniania takich wymaganych metadanych w żądaniach DELETE? Czy są jakieś inne alternatywy, których nie rozważałem?

+1

Niektóre implementacje, takie jak 'Jersey', nie dopuszczają treści dla żądań' delete'. – basiljames

+0

Naprawdę wydaje się, że nie ma dobrej odpowiedzi na ten problem. – niico

Odpowiedz

32

Pomimo pewnych zaleceń, aby nie używać treści wiadomości w przypadku żądań DELETE, takie podejście może być odpowiednie w niektórych przypadkach użycia. Takie podejście wykorzystaliśmy po ocenie innych opcji wymienionych w pytaniu/odpowiedziach i po współpracy z konsumentami usługi.

Podczas gdy użycie treści wiadomości nie jest idealne, żadna z pozostałych opcji nie była idealnie dopasowana. Jednostka DELETE żądania pozwoliła nam łatwo i wyraźnie dodać semantykę wokół dodatkowych danych/metadanych, które były niezbędne do operacji DELETE.

Byłbym nadal otwarty na inne myśli i dyskusje, ale chciałem zamknąć pętlę na to pytanie. Doceniam wszystkie myśli i dyskusje na ten temat!

+7

To jest zły pomysł. Jednym z miejsc, w którym spowoduje to problemy, jest późniejsza decyzja o korzystaniu z usługi akceleracji HTTP, takiej jak Akamai EdgeConnect. Wiem na pewno, że EdgeConnect usuwa ciała z żądań HTTP DELETE (ponieważ zużywają przepustowość są prawdopodobnie nieprawidłowe). Jest również prawdopodobne, że podobne usługi robią to samo (patrz funkcja przyspieszania Kindle'a i inne usługi podobne do CDN). Prawdopodobnie powinieneś przeprojektować, aby nie używać czasowników HTTP do swojej usługi. Większość interfejsów API ma niewielkie znaczenie przy użyciu czasowników HTTP/klasycznych - problemy z transportem usług REST i HTTP są bardzo trudne do rozwiązania. – Gabe

+1

Zgadzam się z @Gabe, wysyłając ciało metodami, które nie mają ciała ** z definicji ** jest pewnym sposobem na przypadkową utratę danych, gdy twoje bity przemierzają rury internetowe, a będziesz miał bardzo trudny czas na debugowanie to. –

5

Biorąc pod uwagę sytuację trzeba, chciałbym mieć jedną z następujących metod:

  • Wysyłanie PUT lub plastra: Jestem wydedukował, że operacja usuwania jest wirtualny, ze względu na charakter konieczności DELETE powód. Dlatego uważam, że aktualizowanie rekordu za pomocą operacji PUT/PATCH jest prawidłowym podejściem, mimo że nie jest to operacja DELETE jako taka.
  • Użyj parametrów zapytania: Zasób uri nie jest zmieniany. Uważam, że jest to również prawidłowe podejście. Pytanie, które łączysz, dotyczyło braku zezwolenia na usunięcie, jeśli brakowało parametru zapytania. W twoim przypadku miałbym tylko domyślny powód, jeśli powód nie jest określony w ciągu zapytania. Zasób będzie nadal resource/:id. Możesz to uczynić wykrywalnym dzięki nagłówkom Link w zasobach dla każdego powodu (z etykietą rel na każdym z nich, aby zidentyfikować przyczynę).
  • Użyj osobnego punktu końcowego według przyczyny: Za pomocą adresu URL, takiego jak resource/:id/canceled. To faktycznie zmienia Request-URI i zdecydowanie nie jest REST. Ponownie, nagłówki linków mogą sprawić, że będzie to wykrywalne.

Pamiętaj, że REST nie jest prawem ani dogmatem. Pomyśl o tym bardziej jako o przewodniku. Tak więc, kiedy nie ma sensu nie stosować się do wskazówek dotyczących twojej domeny problemowej, nie rób tego. Tylko upewnij się, że Twoi klienci korzystający z API są poinformowani o wariancji.

+0

Jeśli chodzi o użycie parametrów zapytań, rozumiem, że zapytanie jest częścią Request-URI na [sekcja 3.2] (http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.2), a zatem stosowanie tego podejścia (lub podobnie, oddzielne punkty końcowe) jest sprzeczne z definicją metody [DELETE] (http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html), tak że " zasób zidentyfikowany przez Request-URI "zostaje usunięty. – shelley

+0

Zasób jest identyfikowany przez ścieżkę URI. Zatem GET do '/ orders /: id' zwróci ten sam zasób, co'/orders /: id? Exclude = orderdetails'. Łańcuch zapytania podaje tylko wskazówki dla serwera - w tym przypadku wyklucza dane porządkowe w odpowiedzi (jeśli są obsługiwane). Podobnie, jeśli wysyłasz polecenie DELETE do '/ orders /: id' lub'/orders /: id? Reason = canceled' lub '/ orders /: id? Reason = bad_credit', nadal działasz na tym samym bazowym zasobie. Aby zachować "jednolity interfejs", miałbym domyślny powód, aby wysyłanie zapytania nie było wymagane. – codeprogression

+0

@shelley Masz rację w swoich obawach dotyczących ciągów zapytań. Ciąg zapytania jest częścią identyfikatora URI. Wysłanie żądania DELETE do '/ foo? 123' oznacza usunięcie innego zasobu niż w przypadku wysłania polecenia DELETE do'/foo? 456'. –

0

Proponuję dołączyć wymagane metadane jako część samej hierarchii URI. Przykład (Naiwny):

Jeśli chcesz usunąć wpisy na podstawie zakresu dat, zamiast podawania daty początkowej i końcowej w treści lub parametrów zapytania, utwórz URI w taki sposób, aby przekazywać wymagane informacje jako część URI.

np.

DELETE /entries/range/01012012/31122012 - Usuń wszystkie wpisy od 01 stycznia 2012 do 31 grudnia 2012

nadzieję, że to pomaga.

+4

Nie obejmuje przypadków takich jak wysłanie powodu usunięcia, np. Pola commment. – Kugel

+2

Wow. To okropny pomysł. Jeśli masz za dużo metadanych, to spowoduje to wzrost ograniczeń rozmiaru na URI. –

+0

To podejście nie stosuje się do praktyk RESTful i nie jest zalecane, ponieważ będziesz miał skomplikowaną strukturę URI. Punkty końcowe zostają pomieszane z powiązaną identyfikacją zasobów z meta-danymi iz czasem staną się koszmarami związanymi z konserwacją, gdy zmienia się interfejs API. O wiele bardziej preferowane jest określenie "zakresu" określonego w zapytaniach lub ładunek, który jest pokarmem tego pytania: zrozumieć podejście do problemu, które, jak powiedziałbym, nie jest tym podejściem. – digitaldreamer

8

Co wydaje się chcieć to jedna z dwóch rzeczy, z których żadna nie jest czystym DELETE:

  1. Masz dwie operacje, z PUT o powód usunięcia następnie DELETE zasobu. Po usunięciu zawartość zasobu nie jest już dostępna dla nikogo. "Przyczyna" nie może zawierać hiperłącza do usuniętego zasobu. Lub
  2. Próbujesz zmienić zasób z state=active na state=deleted, używając metody DELETE.Zasoby ze stanem = usunięte są ignorowane przez główny interfejs API, ale mogą być nadal odczytywane przez administratora lub osobę z dostępem do bazy danych. Jest to dozwolone - DELETE nie musi usuwać danych z kopii zapasowej zasobu, tylko w celu usunięcia zasobu ujawnionego przy tym identyfikatorze URI.

Każda operacja, która wymaga treść wiadomości na żądanie DELETE można podzielić na co to jest najbardziej Generalnie, POST zrobić wszystkie niezbędne zadania z treści wiadomości oraz DELETE. Nie widzę powodu, aby łamać semantykę HTTP.

+2

Co się stanie, jeśli powód "PUT" się powiedzie, a zasób "DELETE" się nie powiedzie? Jak można zapobiec niespójnemu stanowi? – Lightman

+0

@ Lightight the PUT określa tylko intencję. Może istnieć bez odpowiadającego mu DELETE, co wskazywałoby, że ktoś chciał go usunąć, ale albo mu się nie udało, albo zmienili zdanie. Odwrócenie kolejnosci wywołań umożliwiłoby również usunięcie DELETE bez podania przyczyny - podanie przyczyny byłoby wtedy uważane jedynie za adnotację. Z obu tych powodów zalecam użycie opcji 2 z powyższego, tj. Zmianę stanu rekordu bazowego, tak aby zasób HTTP zniknął z bieżącego adresu URL. Garbage collector/admin może następnie usunąć rekordy –