Czy są jakieś problemy z implementacją niestandardowych metod HTTP?

34

Mamy adres URL w następującym formacie

/ instance / {instanceType} / {instanceId}

Możesz to nazwać standardowymi metodami HTTP: POST, GET, DELETE, PUT. Jest jednak kilka innych działań, które podejmujemy, takich jak „Zapisz jako wersję roboczą” lub „Wybawiciel”

Pomyśleliśmy, że możemy po prostu użyć niestandardowych metod HTTP, takich jak: DRAFT, VALIDATE, CURATE

Myślę, że jest to dopuszczalne, ponieważ normy mówią

„Zestaw typowych metod dla HTTP / 1.1 jest zdefiniowany poniżej. Chociaż można go rozszerzyć, nie można założyć, że dodatkowe metody współużytkują tę samą semantykę dla osobno rozszerzonych klientów i serwerów”.

Narzędzia takie jak WebDav tworzą własne rozszerzenia.

Czy są problemy, na które natrafił ktoś przy użyciu niestandardowych metod? Mam na myśli serwery proxy i zapory ogniowe, ale wszelkie inne obszary zainteresowań są mile widziane. Czy powinienem pozostać po bezpiecznej stronie i mieć tylko parametr adresu URL, taki jak action = validate | curate | draft?

Juan Mendes
źródło
6
Cytując ponownie z RFC 1925 - „W projektowaniu protokołu osiągnięto doskonałość nie wtedy, gdy nie ma już nic do dodania, ale kiedy nie ma już nic do zabrania”. - jeśli to działa, nie ma powodu, aby dodawać do http.
4
Nic złego, o ile zdajesz sobie sprawę, że używasz niestandardowego protokołu, a nie HTTP.
user16764
10
@ user16764 „Zestaw typowych metod dla HTTP / 1.1 jest zdefiniowany poniżej. Chociaż można go rozszerzyć, nie można założyć, że dodatkowe metody współużytkują tę samą semantykę dla osobno rozszerzonych klientów i serwerów”. w3.org/Protocols/rfc2616/rfc2616-sec9.html Dlatego jest to dozwolone i nadal jest HTTP
Juan Mendes
imho nie ma nic do dodania / usunięcia z HTTP, ponieważ definicje metod stwierdzają, że stosowanie metod niestandardowych jest już dopuszczalne w zakresie HTTP / 1.1, ale nie można oczekiwać, że będą miały tę samą semantykę, więc sądzę, że zarówno @MichaelT, jak i Juan Mendes mogą być nieco uspokojonym
Prof83

Odpowiedzi:

42

Jednym z podstawowych ograniczeń HTTP oraz z centralnym elementem projektowania reszta to jednolity interfejs dostarczone przez (między innymi) niewielki, stały zestaw metod, które stosuje się powszechnie do wszystkich zasobów. Ujednolicone ograniczenie interfejsu ma wiele zalet i wad. Cytuję z Fielding liberalnie tutaj.

Jednolity interfejs:

  • jest prostsze.
  • oddziela wdrożenia od usług, które świadczą.
  • umożliwia architekturę warstwową, w tym takie elementy, jak usługi równoważenia obciążenia HTTP (nginx) i pamięci podręczne (lakier).

Z drugiej strony jednolity interfejs:

  • obniża wydajność, ponieważ informacje są przesyłane w ustandaryzowanej formie, a nie takiej, która jest specyficzna dla potrzeb aplikacji.

Kompromisy są „zaprojektowane dla powszechnego przypadku sieci” i pozwoliły zbudować duży ekosystem, który zapewnia rozwiązania wielu typowych problemów w architekturze sieci. Przestrzeganie jednolitego interfejsu pozwoli systemowi czerpać korzyści z tego ekosystemu, a jego złamanie utrudni to. Możesz użyć modułu równoważenia obciążenia, takiego jak nginx, ale teraz możesz używać tylko modułu równoważenia obciążenia, który rozumie DRAFT i CURATE. Możesz chcieć użyć warstwy pamięci podręcznej HTTP, takiej jak Varnish, ale teraz możesz używać tylko warstwy pamięci podręcznej HTTP, która obsługuje DRAFT i CURATE. Możesz poprosić kogoś o pomoc w rozwiązywaniu problemów z awarią serwera, ale nikt inny nie zna semantyki żądania CURATE. Zmiana preferowanych bibliotek klienta lub bibliotek serwera może być trudna do zrozumienia i prawidłowego wdrożenia nowych metod. I tak dalej.

Prawidłowym * sposobem na przedstawienie tego jest transformacja stanu zasobu (lub zasobów pokrewnych). Nie tworzysz posta, transformujesz jego draftstan truelub tworzysz draftzasób, który zawiera zmiany i linki do poprzednich wersji roboczych. Nie LECZESZ posta, transformujesz jego curatedstan truelub tworzysz curationzasób, który łączy post z użytkownikiem, który go wyleczył.

* Prawidłowe, ponieważ najściślej przestrzega zasad architektury REST.

Rein Henrichs
źródło
Dzięki za komentarze na temat równoważenia obciążenia, na pewno przyjrzę się temu. Czy znasz zasób określający, czy metody niestandardowe są dopuszczalne, czy nie?
Juan Mendes
2
Nie widzę żadnej korzyści z niestandardowych metod, chyba że są one częścią szeroko obsługiwanego rozszerzenia, takiego jak WEBDAV (a nawet wtedy, nie tak bardzo), więc nigdy nie przyjrzałem się temu. Po prostu poleciłbym potraktować te zmiany jako transformacje stanu. Sieć działa dobrze z metodami, które już mamy. Naprawdę nie ma dobrego powodu, aby dodawać więcej, chyba że mają one sens jako część jednolitego interfejsu (np. PATCH).
Rein Henrichs
5
Widzę zaletę w projektowaniu sposobu, w jaki usługa HTTP ma działać dla siebie. jednak „nie można założyć, że dodatkowe metody dzielą tę samą semantykę” - wystarczająco dobrze, ALE wciąż jest częścią zakresu HTTP / 1.1, dlatego zapory ogniowe, serwery proxy, usługi równoważenia obciążenia i tym podobne powinny umożliwiać taką możliwość, jeśli nie Czy zatem nie wdrażają poprawnie protokołu HTTP / 1.1?
Prof83
Prawdopodobnie pochodzisz ze spokojnego POV, jednak nie rozumiem, dlaczego czasowniki niestandardowe powinny stanowić problem. Wszystkie narzędzia powinny traktować je jak POST, tzn. „Zasób prawdopodobnie się zmienia i to wszystko, co wiemy”.
maaartinus
7

Wolałbym zaprojektować je jako pod-zasoby, na które wykonujesz żądanie POST.

Biorąc pod uwagę, że masz zasób /instance/type/1, chciałbym, aby reprezentacja tego zasobu zawierała kilka linków do „działań”, które można wykonać na zasobie, takich jak /instance/type/1/drafti /instance/type/1/curate. W JSON może to być tak proste, jak:

{
    "some property":"the usual value",
    "state": "we can still inform the client about the current state",
    "draft": "http://server/instance/type/1/draft",
    "curate": "http://server/instance/type/1/curate"
}

Dzięki temu klient może bardzo wyraźnie powiedzieć, co musi się zdarzyć, podczas żądania POST do linku podanego przez curateczłonka. Umieszczony tam zasób może zawierać argumenty opisujące zdarzenie, które być może spowodują zmianę stanu.

Stosowanie „naiwnego” podejścia polegającego na przechodzeniu między możliwymi stanami zasobu ma tę wadę, że nie rejestruje zdarzeń, które doprowadziły do ​​tych przejść.

Przejścia stanu zwykle następują w odpowiedzi na określone zdarzenia i wolę uchwycić te zdarzenia, niż pozwolić klientowi zdecydować, że coś jest teraz w określonym „stanie”. Utrudnia to również walidację. Ponadto nie będziesz w stanie uchwycić żadnych „argumentów”, chyba że opisujesz również te w samym stanie. A potem robi się niedobrze, gdy jakiś kod zmienia te bez rzeczywistego przejścia stanu i wymagana jest weryfikacja, a wszystko szybko staje się bałaganem.

Dave Van den Eynde
źródło
Dobra odpowiedź. Zdolność dostarczania argumentów do przejść do stanu i umożliwienia ich enkapsulacji i zarządzania przez serwer jest zdecydowanie najlepszym podejściem.
Thomas W
Firma, w której aktualnie pracuję (VMware), robi to. GET na /vms/some-idzwraca linki do akcji takich jak POST /vms/some-id/restarti używamy go do ustalenia, czy akcje powinny być włączone czy wyłączone. Mam związek miłości / nienawiści z HATEOAS :)
Juan Mendes
Byłoby o wiele bardziej sensowne, gdyby podejmowane działanie było czasownikiem żądania w stosunku do jakiegoś losowego parametru zapytania, segmentu ścieżki zasobów lub właściwości ciała.
Matthew Whited
Nie możesz linkować do czasownika.
Dave Van den Eynde
6

Myślę, że niestandardowa metoda HTTP jest najlepszym sposobem na wdrożenie działań encji. Dodanie akcji do ciała encji (POST) wydaje się niewłaściwe, nie jest częścią twojej encji (chociaż wynik może zostać w niej zapisany). Ponadto za pomocą niestandardowych metod HTTP serwery proxy mogą określać ich działania bez konieczności analizowania treści encji.

To jest jak CRUD, zawsze chciałbyś je wdrożyć, ale masz też swój własny zestaw akcji (na enitity). Naprawdę nie rozumiem, jaki byłby problem z ich przedłużeniem.

Również @Rein Henrichs „Nie tworzysz posta, zmieniasz jego stan szkicu na prawdziwy lub tworzysz zasób szkicu” wydaje mi się fałszywy. draftsNieruchomość będą wykorzystywane do zapisywania trwały stan, a nie do dokonywania transformacji. Działania niekoniecznie prowadzą do „stanu” lub nie są zapisywane we właściwości. Tworzenie osobnego bytu dla każdego stanu / transformacji wydaje się jeszcze bardziej rozmyte. Spróbuj zachować to samo odwołanie (URI) do enity.

Robert de W
źródło
1
Jest to słuszna kwestia, choć nie zgadzano się z nią, widzę uzasadnienie i nie zgadzam się z opinią negatywną (szczególnie bez komentarza wyborcy). Weźmy jako przykład obsługę wyjątków PHP, „najlepsza praktyka” wydaje się skłaniać ku użyciu określonych typów wyjątków, aby zasugerować rodzaj wyjątku, nawet ignorując rzeczywisty komunikat, taki jak RuntimeException vs BadMethodCallException. Dlaczego więc jest tak szeroko argumentowane przeciwko używaniu DRAFT, jeśli stosowanie metod niestandardowych jest już uważane za część zakresu HTTP / 1.1?
Równoważenie