PUT vs. POST w REST

5370

Zgodnie ze specyfikacją HTTP / 1.1:

POSTMetoda służy do wniosku, że serwer pochodzenie zaakceptować podmiot ujęty w żądaniu jako nowy podległych zasobu zidentyfikowanych przez Request-URIwRequest-Line

Innymi słowy, POSTsłuży do tworzenia .

Te PUTwnioski, że metoda zamknięta jednostka być przechowywane pod dostarczony Request-URI. Jeśli Request-URIodnosi się do już istniejącego zasobu, zamknięty obiekt MUSI być uważany za zmodyfikowaną wersję tego, który znajduje się na serwerze źródłowym. Jeśli Request-URInie wskazuje na istniejący zasób, a ten identyfikator URI może zostać zdefiniowany jako nowy zasób przez żądającego agenta użytkownika, serwer źródłowy może utworzyć zasób z tym identyfikatorem URI. ”

Oznacza to, że PUTsłuży do tworzenia lub zastępowania .

Którego należy użyć do stworzenia zasobu? Czy trzeba wspierać oba?

alex
źródło
56
Pomocne może być użycie definicji w HTTPbis - Roy włożył sporo pracy w ich wyjaśnienie. Patrz: tools.ietf.org/html/…
Mark Nottingham,
16
Aby wprowadzić komentarz @ MarkNottingham do najnowszej wersji, oto POST i PUT , zgodnie z definicją w HTTPbis.
Marius Butuc
37
Wydaje mi się, że ta debata powstała w wyniku powszechnej praktyki nadmiernego upraszczania REST poprzez opisanie metod HTTP w kategoriach operacji CRUD.
Stuporman
5
Niestety pierwsze odpowiedzi są błędne na temat testu POST. Sprawdź moją odpowiedź, aby uzyskać lepsze wyjaśnienie różnic: stackoverflow.com/a/18243587/2458234
7hi4g0
23
PUT i POST to niebezpieczne metody. Jednak PUT jest idempotentny, podczas gdy POST nie. - Zobacz więcej na: restcookbook.com/HTTP%20Methods/put-vs-post/…
Dinesh Saini

Odpowiedzi:

4236

Ogólnie:

Do tworzenia można użyć zarówno PUT, jak i POST.

Musisz zapytać „do czego wykonujesz akcję?” aby rozróżnić, czego powinieneś używać. Załóżmy, że projektujesz interfejs API do zadawania pytań. Jeśli chcesz użyć POST, zrobiłbyś to z listą pytań. Jeśli chcesz użyć PUT, zrobiłbyś to dla konkretnego pytania.

Można używać zarówno jednego, jak i drugiego w moim projekcie RESTful:

Nie musisz obsługiwać zarówno PUT, jak i POST.

To, co jest używane, należy do Ciebie. Pamiętaj jednak, aby użyć właściwego w zależności od tego, do którego obiektu odwołujesz się w żądaniu.

Kilka uwag:

  • Czy wyraźnie określasz nazwy obiektów URL, które tworzysz, czy też serwer decyduje? Jeśli je nazwiesz, użyj PUT. Jeśli pozwolisz serwerowi podjąć decyzję, użyj POST.
  • PUT jest idempotentny, więc jeśli umieścisz obiekt dwa razy, nie da to efektu. To ładna właściwość, więc w miarę możliwości skorzystałbym z PUT.
  • Możesz zaktualizować lub utworzyć zasób za pomocą PUT z tym samym adresem URL obiektu
  • Dzięki POST możesz jednocześnie otrzymywać 2 żądania, wprowadzając zmiany do adresu URL i mogą one aktualizować różne części obiektu.

Przykład:

Napisałem następujące jako część innej odpowiedzi na SO w tej sprawie :

POCZTA:

Służy do modyfikowania i aktualizowania zasobu

POST /questions/<existing_question> HTTP/1.1
Host: www.example.com/

Zauważ, że następujący błąd:

POST /questions/<new_question> HTTP/1.1
Host: www.example.com/

Jeśli adres URL nie został jeszcze utworzony, nie powinieneś używać POST, aby go utworzyć, podając nazwę. Powinno to spowodować błąd „nie znaleziono zasobu”, ponieważ <new_question>jeszcze nie istnieje. <new_question> Najpierw umieść zasób na serwerze.

Możesz jednak zrobić coś takiego, aby utworzyć zasoby za pomocą POST:

POST /questions HTTP/1.1
Host: www.example.com/

Zauważ, że w tym przypadku nazwa zasobu nie jest określona, ​​ścieżka URL nowego obiektu zostanie zwrócona.

POŁOŻYĆ:

Służy do tworzenia zasobu lub zastępowania go. Podczas określania zasobów nowy adres URL.

W przypadku nowego zasobu:

PUT /questions/<new_question> HTTP/1.1
Host: www.example.com/

Aby zastąpić istniejący zasób:

PUT /questions/<existing_question> HTTP/1.1
Host: www.example.com/

Dodatkowo i nieco bardziej zwięźle, RFC 7231 Sekcja 4.3.4 Stany PUT (wyróżnienie dodane),

4.3.4 POŁOŻYĆ

Metoda PUT żąda, aby stan zasobu docelowego był createdlub replacedze stanem zdefiniowanym przez reprezentację zawartą w ładunku komunikatu żądania.

Brian R. Bondy
źródło
1026
Myślę, że nie można wystarczająco podkreślić faktu, że PUT jest idempotentny: jeśli sieć jest spartaczona, a klient nie jest pewien, czy jego żądanie się udało, może po prostu wysłać ją drugi (lub setny) raz i jest to gwarantowane przez Specyfikacja HTTP, że ma to dokładnie taki sam efekt, jak jednorazowe wysłanie.
Jörg W Mittag
77
@ Jörg W Mittag: Niepotrzebne. Drugi raz może zwrócić 409 Konflikt lub coś, jeśli żądanie zostało w międzyczasie zmodyfikowane (przez innego użytkownika lub samo pierwsze żądanie, które przeszło).
Mitar
630
Jeśli się nie mylę, powinniśmy podkreślić, że PUT jest zdefiniowany jako idempotentny. Nadal musisz pisać serwer w taki sposób, aby PUT zachowywał się poprawnie, tak? Być może lepiej powiedzieć „PUT powoduje, że transport przyjmuje idempotencję, co może wpływać na zachowanie transportu, np. Buforowanie”.
Ian Ni-Lewis,
150
@ JörgWMittag Hasło idempotencji? Co powiesz na „Wysyłaj i wysyłaj i wysyłaj mojego przyjaciela, to nie ma znaczenia na końcu”.
James Beninger
39
Traktuje je jako: PUT = wstaw lub aktualizuj; POST = wstaw. Więc kiedy zrobisz dwa PUT - otrzymasz jeden nowy rekord, kiedy zrobisz dwa POST - otrzymasz dwa nowe rekordy.
Eugen Konkov,
2217

W Internecie można znaleźć twierdzenia, które mówią

Żadne z nich nie ma racji.


Lepiej jest wybierać między PUT a POST w oparciu o idempotencję akcji.

PUT oznacza umieszczenie zasobu - całkowite zastąpienie tego, co jest dostępne pod danym adresem URL, inną rzeczą. Z definicji PUT jest idempotentny. Zrób to tyle razy, ile chcesz, a wynik będzie taki sam. x=5jest idempotentny. Możesz PUT zasób, czy już istnieje, czy nie (np. W celu utworzenia lub aktualizacji)!

POST aktualizuje zasób, dodaje zasób pomocniczy lub powoduje zmianę. POST nie jest idempotentny w sposób, który x++nie jest idempotentny.


Według tego argumentu PUT służy do tworzenia, gdy znasz adres URL rzeczy, którą utworzysz. POST można wykorzystać do utworzenia, gdy znasz adres URL „fabryki” lub menedżera dla kategorii rzeczy, którą chcesz utworzyć.

więc:

POST /expense-report

lub:

PUT  /expense-report/10929
Cheeso
źródło
72
Zgadzam się, że wszędzie tam, gdzie chodzi o idempotencję, powinna ona rozwiać wszelkie inne obawy, ponieważ pomyłka może spowodować wiele nieoczekiwanych błędów.
Josh
16
Jeśli POST może zaktualizować zasób, to dlaczego nie jest to idempotentne? Jeśli zmienię wiek uczniów za pomocą PUT i zrobię to 10 razy, to wiek uczniów będzie taki sam, jeśli zrobię to raz.
Jack Ukleja,
28
@ Schneider, w tym przypadku Twój serwer dokłada dodatkowych starań, aby zagwarantować idempotencję, ale nie reklamuje tego. Przeglądarki nadal ostrzegają użytkownika, jeśli spróbują ponownie załadować takie żądanie POST.
Tobu,
47
@ Schneider POST może utworzyć zasób pomocniczy; dlatego możesz POST do zbierania, jak POST / raporty wydatków, i utworzyłoby tyle jednostek (raportów wydatków) na twoim serwerze, ile wysłanych żądań, nawet jeśli są całkowicie podobne. Pomyśl o tym jako o wstawianiu tego samego wiersza do tabeli DB (/ raporty wydatków) z automatycznie zwiększanym kluczem podstawowym. Dane pozostają takie same, klucz (w tym przypadku URI) jest generowany przez serwer i jest inny dla każdej innej wstawki (żądania). Więc efekt POST może być idempotent, ale również może nie. Dlatego POST nie jest idempotentny.
Snifff,
11
Powiedzmy, że mamy byty, które mogą mieć dwie właściwości - namei date. Jeśli mamy jednostkę z istniejącą namei date, ale następnie dokonać żądania do niego określające jedynie name, właściwe zachowanie PUT byłoby zatrzeć datepodmiotu, podczas POST może aktualizować określony tylko właściwości, pozostawiając właściwości nieokreślone, gdyż były one przed złożeniem wniosku. Czy to brzmi poprawnie / rozsądnie, czy też jest to niewłaściwe użycie PUT (widziałem odniesienia do PATCH , które wydają się bardziej odpowiednie, ale jeszcze nie istnieją)?
Jon z
706
  • POST do adresu URL tworzy zasób potomny pod adresem URL zdefiniowanym na serwerze .
  • PUT do adresu URL tworzy / zastępuje zasób w całości pod adresem URL zdefiniowanym przez klienta .
  • PATCH do adresu URL aktualizuje część zasobu pod tym adresem URL zdefiniowanym przez klienta.

Odpowiednia specyfikacja dla PUT i POST to RFC 2616 §9.5ff.

POST tworzy zasób podrzędny , więc POST /itemstworzy zasoby znajdujące się pod /itemszasobem. Na przykład. /items/1. Dwukrotne wysłanie tego samego pakietu pocztowego spowoduje utworzenie dwóch zasobów.

PUT służy do tworzenia lub zastępowania zasobu pod adresem URL znanym przez klienta .

Dlatego: PUT jest tylko kandydatem do utworzenia, w którym klient zna adres URL przed utworzeniem zasobu. Na przykład. /blogs/nigel/entry/when_to_use_post_vs_putponieważ tytuł jest używany jako klucz zasobu

PUT zastępuje zasób pod znanym adresem URL, jeśli już istnieje, więc dwukrotne wysłanie tego samego żądania nie przynosi żadnego efektu. Innymi słowy, połączenia do PUT są idempotentne .

RFC brzmi następująco:

Podstawowa różnica między żądaniami POST i PUT znajduje odzwierciedlenie w innym znaczeniu URI żądania. Identyfikator URI w żądaniu POST identyfikuje zasób, który będzie obsługiwał zamknięty obiekt. Ten zasób może być procesem akceptującym dane, bramą do innego protokołu lub osobnym podmiotem, który przyjmuje adnotacje. W przeciwieństwie do tego, URI w żądaniu PUT identyfikuje encję dołączoną do żądania - agent użytkownika wie, jaki jest URI, a serwer NIE MOŻE próbować zastosować żądania do jakiegoś innego zasobu. Jeśli serwer chce zastosować żądanie do innego identyfikatora URI,

Uwaga: PUT był głównie używany do aktualizacji zasobów (poprzez zastąpienie ich w całości), ale ostatnio nastąpił ruch w kierunku użycia PATCH do aktualizacji istniejących zasobów, ponieważ PUT określa, że ​​zastępuje cały zasób. RFC 5789.

Aktualizacja 2018 : Istnieje możliwość, aby uniknąć PUT. Zobacz „REST bez PUT”

W przypadku techniki „REST bez PUT” chodzi o to, że konsumenci są zmuszeni wysyłać nowe „nieużywane” zasoby żądań. Jak wspomniano wcześniej, zmiana adresu pocztowego klienta jest testem POST na nowy zasób „ChangeOfAddress”, a nie PUT zasobu „Customer” z inną wartością pola adresu pocztowego.

zaczerpnięte z REST API Design - Modelowanie zasobów autorstwa Prakash Subramaniam z Thoughtworks

Zmusza to interfejs API do unikania problemów ze zmianą stanu przy wielu klientach aktualizujących pojedynczy zasób i lepiej pasuje do pozyskiwania zdarzeń i CQRS. Gdy praca jest wykonywana asynchronicznie, właściwe wydaje się POST transformacji i oczekiwanie na jej zastosowanie.

Nigel Thorne
źródło
53
Lub z drugiej strony ogrodzenia: PUT, jeśli klient określi adres zasobu wynikowego, POST, jeśli serwer to zrobi.
DanMan
3
Myślę, że odpowiedź powinna zostać zredagowana, aby wyjaśnić, co @DanMan wskazał w bardzo prosty sposób. Najbardziej cenię tu notatkę na końcu, stwierdzającą, że PUT powinien być używany tylko do zastąpienia całego zasobu.
Hermes,
3
PATCH nie jest realistyczną opcją przez co najmniej kilka lat, ale zgadzam się z ideologią.
zmiażdżyć
4
Próbuję to zrozumieć, ale użycie PUT do stworzenia czegoś miałoby sens tylko wtedy, gdyby klient wiedział na pewno, że zasób jeszcze nie istnieje, prawda? Podążając za przykładem bloga, powiedz, że utworzyłeś setki postów na blogu w ciągu kilku lat, a następnie przypadkowo wybrałeś ten sam tytuł, jak w przypadku postu dwa lata temu. Teraz odszedłeś i zastąpiłeś ten post, co nie było zamierzone. Więc użycie PUT do tworzenia wymagałoby od klienta śledzenia tego, co jest podejmowane, a co nie, i może prowadzić do wypadków i niezamierzonych skutków ubocznych, a także do posiadania tras, które wykonują dwie zupełnie różne rzeczy?
galaxyAbstractor
5
Masz rację. Umieszczenie posta na blogu pod tym samym adresem URL co istniejący spowodowałoby aktualizację tego istniejącego postu (chociaż oczywiście możesz najpierw sprawdzić za pomocą GET). Wskazuje to, dlaczego używanie samego tytułu jako adresu URL byłoby złym pomysłem. Działa to jednak wszędzie tam, gdzie w danych był naturalny klucz ... co z mojego doświadczenia jest rzadkie. Lub jeśli użyłeś GUID
Nigel Thorne
221

Podsumowanie:

Stwórz:

Można to wykonać za pomocą PUT lub POST w następujący sposób:

POŁOŻYĆ

Tworzy THE nowy zasób z newResourceId jako identyfikator, pod / zasobów URI, lub zbiórki .

PUT /resources/<newResourceId> HTTP/1.1 

POCZTA

Tworzy A nowy zasób pod resources / URI lub kolekcji . Zwykle identyfikator jest zwracany przez serwer.

POST /resources HTTP/1.1

Aktualizacja:

Może tylko być wykonane z PP w następujący sposób:

POŁOŻYĆ

Aktualizuje zasób o istniejący identyfikatorResourceId jako identyfikator w identyfikatorze URI / resources lub kolekcji .

PUT /resources/<existingResourceId> HTTP/1.1

Wyjaśnienie:

Kiedy masz do czynienia z REST i URI jako ogólnym, masz ogólny po lewej, a konkretny po prawej . Te leki generyczne są zazwyczaj nazywane zbiory i więcej konkretnych przedmiotów można nazwać zasobem . Pamiętaj, że zasób może zawierać kolekcję .

Przykłady:

<- ogólny - specyficzny ->

URI: website.com/users/john
website.com  - whole site
users        - collection of users
john         - item of the collection, or a resource

URI:website.com/users/john/posts/23
website.com  - whole site
users        - collection of users
john         - item of the collection, or a resource
posts        - collection of posts from john
23           - post from john with identifier 23, also a resource

Kiedy korzystasz z POST, zawsze masz na myśli kolekcję , więc za każdym razem, gdy mówisz:

POST /users HTTP/1.1

publikujesz nowego użytkownika w kolekcji użytkowników .

Jeśli będziesz kontynuować i wypróbować coś takiego:

POST /users/john HTTP/1.1

będzie działać, ale semantycznie mówisz, że chcesz dodać zasób do kolekcji John w ramach kolekcji użytkowników .

Kiedy używasz PUT, odnosisz się do zasobu lub pojedynczego elementu, być może wewnątrz kolekcji . Więc kiedy powiesz:

PUT /users/john HTTP/1.1

powiadamiasz o aktualizacji serwera lub utwórz, jeśli nie istnieje, zasób Johna w kolekcji użytkowników .

Specyfikacja:

Pozwól, że podkreślę kilka ważnych części specyfikacji:

POCZTA

Metoda POST służy do żądania, aby serwer źródłowy zaakceptował jednostkę zawartą w żądaniu jako nowego podwładnego zasobu określonego przez identyfikator URI żądania w wierszu żądania

Dlatego tworzy nowy zasób w kolekcji .

POŁOŻYĆ

Metoda PUT żąda, aby zamknięta jednostka była przechowywana pod dostarczonym URI żądania. Jeśli identyfikator URI żądania odnosi się do już istniejącego zasobu, dołączony byt MUSI być uważany za zmodyfikowaną wersję tego, który znajduje się na serwerze źródłowym. Jeśli identyfikator URI żądania nie wskazuje na istniejący zasób, a ten identyfikator URI może zostać zdefiniowany jako nowy zasób przez żądającego agenta użytkownika, serwer źródłowy może utworzyć zasób z tym identyfikatorem URI. ”

Dlatego utwórz lub zaktualizuj w oparciu o istnienie zasobu .

Odniesienie:

7hi4g0
źródło
11
Ten post był dla mnie pomocny w zrozumieniu, że POST dodaje „coś” jako dziecko do danej kolekcji (URI), podczas gdy PUT wyraźnie definiuje „coś” w danej lokalizacji URI.
kwah
3
Myślę, że to najlepsza odpowiedź: żaden z tych nonsensów „POST nie może zaktualizować zasobu”. Podoba mi się twoje stwierdzenie: „Aktualizacja może być wykonana tylko z PUT”.
Thomas
4
Nie, PUT nie jest przeznaczony do aktualizacji ani tworzenia. To jest do wymiany. Pamiętaj, że nic nie możesz zastąpić czymś, co daje efekt tworzenia.
thecoshman
2
@ 7hi4g0 PUT służy do aktualizacji z całkowitym zastąpieniem, innymi słowy, zastępuje. Nic nie zastępujesz czymś lub czymś całkowicie nowym. PUT nie służy do wprowadzania drobnych zmian (chyba że klient wprowadzi tę niewielką zmianę i dostarczy całą nową wersję, nawet to, co pozostanie niezmienione). W przypadku częściowej modyfikacji PATCH jest metodą z wyboru.
thecoshman
1
@ thecoshman Mógłbyś, ale nie byłoby zbyt jasne, że tworzenie jest tam również objęte. W takim przypadku lepiej jest być wyraźnym.
7hi4g0
175

POST oznacza „utwórz nowy” jak w „Oto dane wejściowe do tworzenia użytkownika, utwórz go dla mnie”.

PUT oznacza „wstaw, zamień, jeśli już istnieje”, jak w „Oto dane dla użytkownika 5”.

Jesteś POSTna example.com/users, ponieważ nie znasz URLjeszcze użytkownika, chcesz, aby serwer go utworzył.

Ty PUTdo example.com/users/id skoro chcesz wymienić / stworzenia konkretnego użytkownika.

Dwukrotne wysłanie przy użyciu tych samych danych oznacza utworzenie dwóch identycznych użytkowników o różnych identyfikatorach. SKŁADANIE dwukrotnie przy użyciu tych samych danych tworzy użytkownika jako pierwszy i aktualizuje go do tego samego stanu za drugim razem (bez zmian). Ponieważ skończysz z tym samym stanem, PUTbez względu na to, ile razy go wykonasz, mówi się, że za każdym razem jest „równie silny” - idempotentny. Jest to przydatne do automatycznego ponawiania żądań. Nigdy więcej „czy na pewno chcesz wysłać ponownie” po naciśnięciu przycisku Wstecz w przeglądarce.

Ogólna rada jest przydatna, POSTgdy potrzebujesz, aby serwer kontrolował URLgenerowanie zasobów. Użyj PUTinaczej. Wolę PUT ponad POST.

Alexander Torstling
źródło
12
Niechlujstwo może powodować, że powszechnie naucza się, że potrzebujesz tylko dwóch czasowników: GET i POST. GET, aby uzyskać, POST, aby zmienić. Nawet PUT i DELETE zostały wykonane przy użyciu POST. Pytanie o to, co tak naprawdę oznacza PUT, może 25 lat później może być znakiem, że nauczyliśmy się tego na początku źle. Popularność REST sprawiła, że ​​ludzie wrócili do podstaw, w których musimy teraz oduczyć się przeszłych błędów. POST był nadużywany i obecnie powszechnie nauczany niepoprawnie. Najlepsza część: „Dwukrotne wysłanie z tymi samymi danymi oznacza utworzenie dwóch identycznych [zasobów]”. Świetny punkt!
maxpolk
1
Jak możesz użyć PUT do utworzenia rekordu według identyfikatora, tak jak w twoim przykładzie, user 5jeśli jeszcze nie istnieje? Nie masz na myśli update, replace if already exists? czy coś
Łukasz
@Coulton: Miałem na myśli to, co napisałem. Wstawiasz użytkownika 5, jeśli wstawiasz do / users / 5, a # 5 jeszcze nie istnieje.
Alexander Torstling
@Coulton: PUTMożna go również wykorzystać do zastąpienia wartości istniejącego zasobu w całości.
DavidRR,
1
„Preferuj PUT zamiast POST” ... chcesz to uzasadnić?
thecoshman
173

Chciałbym dodać moją „pragmatyczną” radę. Użyj PUT, jeśli znasz „identyfikator”, przez który można zapisać zapisany obiekt. Korzystanie z PUT nie będzie działać zbyt dobrze, jeśli potrzebujesz, powiedzmy, wygenerowanego identyfikatora bazy danych, który zostanie zwrócony, abyś mógł przeprowadzić przyszłe wyszukiwania lub aktualizacje.

Zatem: Aby zapisać istniejącego użytkownika lub takiego, w którym klient generuje identyfikator i zweryfikowano, że identyfikator jest unikalny:

PUT /user/12345 HTTP/1.1  <-- create the user providing the id 12345
Host: mydomain.com

GET /user/12345 HTTP/1.1  <-- return that user
Host: mydomain.com

W przeciwnym razie użyj POST do początkowego utworzenia obiektu, a PUT do zaktualizowania obiektu:

POST /user HTTP/1.1   <--- create the user, server returns 12345
Host: mydomain.com

PUT /user/12345 HTTP/1.1  <--- update the user
Host: mydomain.com
ThaDon
źródło
17
Właściwie tak powinno być POST /users. (Uwaga: /usersliczba mnoga.) Ma to wpływ na utworzenie nowego użytkownika i uczynienie go podrzędnym zasobem /userskolekcji.
DavidRR,
6
@DavidRR, aby być uczciwym, jak obchodzić się z grupami, to kolejna debata. GET /usersma sens, czyta tak, jak chcesz, ale byłbym w porządku z ( GET /user/<id>lub POST /userz ładunkiem dla wspomnianego nowego użytkownika), ponieważ poprawnie odczytuje „get me users 5” jest dziwne, ale „get me user 5” jest bardziej naturalne. Prawdopodobnie nadal
upadłbym
126

Użyj POST, aby utworzyć, a PUT, aby zaktualizować. Tak zresztą Ruby on Rails to robi.

PUT    /items/1      #=> update
POST   /items        #=> create
Tim Sullivan
źródło
4
POST /itemsdodaje nowy element do już zdefiniowanego zasobu („element”). Jak mówi odpowiedź, „nie tworzy grupy”. Nie rozumiem, dlaczego ma 12 głosów.
David J.
Po wyjęciu z pudełka Railsy nie obsługują „tworzenia grupy” przez REST. Aby „utworzyć grupę”, co oznacza „utwórz zasób”, musisz to zrobić za pomocą kodu źródłowego.
David J.
8
Jest to uczciwa wytyczna, ale nadmierne uproszczenie. Jak wspomniano w innych odpowiedziach, do tworzenia i aktualizacji można użyć dowolnej metody.
Brad Koch
2
Zgadzam się z odpowiedzią z niewielką modyfikacją. Użyj POST, aby utworzyć i PUT, aby całkowicie zaktualizować zasób. Do częściowych aktualizacji możemy użyć PUT lub PATCH. Powiedzmy, że chcemy zaktualizować status grupy. Możemy użyć PUT / groups / 1 / status ze statusem to ładunek żądania lub PATCH / groups / 1 ze szczegółami dotyczącymi akcji w ładunku
java_geek
2
Należy również wyjaśnić, że dotyczy PUT /items/42to również tworzenia zasobu, ale tylko wtedy, gdy klient ma uprawnienia do nadawania nazwy zasobowi . (Czy Railsy
dają
123

Oba są używane do transmisji danych między klientem a serwerem, ale istnieją między nimi subtelne różnice, które są:

Wpisz opis zdjęcia tutaj

Analogia:

  • PUT tj. Weź i umieść tam, gdzie to było.
  • POST jak wysłać pocztę na poczcie .

wprowadź opis zdjęcia tutaj

Analogia mediów społecznościowych / sieci:

  • Publikuj w mediach społecznościowych: gdy publikujemy wiadomość, tworzona jest nowa wiadomość.
  • Wpisz (tj. Edytuj) wiadomość, którą już wysłaliśmy.
Premraj
źródło
21
@MobileMon Nie, metody REST nie są CRUD.
jlr
1
Powiedziałbym PUT dla UPSERTS
Hola Soy Edu Feliz Navidad
@MobileMon no: POST podczas tworzenia nowego zasobu i nie znasz ostatecznego punktu końcowego, aby go zdobyć. PUT dla innych przypadków.
Portekoi
67

REST to koncepcja bardzo wysokiego poziomu. W rzeczywistości nawet nie wspomina o HTTP!

Jeśli masz wątpliwości, jak zaimplementować REST w HTTP, zawsze możesz spojrzeć na specyfikację Atom Publication Protocol (AtomPub) . AtomPub jest standardem do pisania usług internetowych RESTful z HTTP, który został opracowany przez wiele źródeł HTTP i REST, z pewnymi danymi wejściowymi od Roy Fieldinga, wynalazcy REST i (współ) wynalazcy samego HTTP.

W rzeczywistości może być nawet możliwe bezpośrednie użycie AtomPub. Wyszedł ze społeczności blogerów, ale w żaden sposób nie ogranicza się do blogowania: jest to ogólny protokół do RESTYFIKACJI interakcji z dowolnymi (zagnieżdżonymi) kolekcjami dowolnych zasobów za pośrednictwem protokołu HTTP. Jeśli możesz reprezentować swoją aplikację jako zagnieżdżoną kolekcję zasobów, możesz po prostu użyć AtomPub i nie martw się, czy użyć PUT, czy POST, jakie kody stanu HTTP zwrócić i wszystkie te szczegóły.

Oto, co AtomPub ma do powiedzenia na temat tworzenia zasobów (sekcja 9.2):

Aby dodać członków do kolekcji, klienci wysyłają żądania POST do identyfikatora URI kolekcji.

Jörg W Mittag
źródło
8
Nie ma nic złego w zezwoleniu PUT na tworzenie zasobów. Pamiętaj tylko, że oznacza to, że klient podaje adres URL.
Julian Reschke,
5
Jest coś bardzo złego w zezwoleniu PUT na tworzenie zasobów: klient podaje adres URL. To zadanie serwera!
Joshcodes
@Joshcodes Nie zawsze jest tak, że zadaniem serwera jest tworzenie identyfikatorów klienta. Coraz częściej widzę projekty, które pozwalają klientom generować UUID jako identyfikator zasobu. Ta konstrukcja nadaje się szczególnie do zwiększenia skali.
Justin Ohms
@JustinOhms Zgadzam się z twoją opinią na temat identyfikatorów generowanych przez klienta (uwaga: wszystkie systemy zaprojektowane przeze mnie od około 2008 roku wymagają od klienta utworzenia identyfikatora jako UUID / Guid). To nie znaczy, że klient powinien podać adres URL.
Joshcodes
1
Tak, jeśli zasób już istnieje, użyj PUT. Jednak w prawie wszystkich przypadkach zasoby należy utworzyć za pomocą POST, a klient nie powinien podawać adresu URL. Roy Fielding zgadza się z tym oświadczeniem FWIW: roy.gbiv.com/untangled/2008/rest-apis-must-be-hypertext-driven
Joshcodes
61

Decyzja, czy użyć PUT, czy POST do utworzenia zasobu na serwerze z interfejsem API HTTP + REST, zależy od tego, kto jest właścicielem struktury adresu URL. Poinformowanie klienta lub uczestnictwo w jego definiowaniu, struktura URL jest niepotrzebnym sprzężeniem podobnym do niepożądanych połączeń, które powstały w wyniku SOA. Unikanie rodzajów połączeń jest powodem, dla którego REST jest tak popularny. Dlatego właściwą metodą jest POST. Istnieją wyjątki od tej reguły i występują one, gdy klient chce zachować kontrolę nad strukturą lokalizacji wdrażanych zasobów. Jest to rzadkie i prawdopodobnie oznacza, że ​​coś innego jest nie tak.

W tym momencie niektóre osoby będą argumentować, że jeśli używane są RESTful-URL , klient zna adres URL zasobu i dlatego PUT jest akceptowalny. W końcu dlatego kanoniczne, znormalizowane, Ruby on Rails, adresy URL Django są ważne, spójrz na API na Twitterze… bla bla bla. Ci ludzie muszą zrozumieć, że nie ma czegoś takiego jak Restful-URL, a sam Roy Fielding stwierdza, że :

Interfejs API REST nie może definiować stałych nazw zasobów ani hierarchii (oczywiste połączenie klienta i serwera). Serwery muszą mieć swobodę kontrolowania własnej przestrzeni nazw. Zamiast tego pozwól serwerom instruować klientów, jak konstruować odpowiednie identyfikatory URI, na przykład w formularzach HTML i szablonach URI, poprzez zdefiniowanie tych instrukcji w typach multimediów i relacjach między linkami. [Niepowodzenie w tym przypadku oznacza, że ​​klienci przyjmują strukturę zasobów z powodu informacji poza pasmem, takich jak specyficzny dla domeny standard, który jest zorientowanym na dane odpowiednikiem sprzężenia funkcjonalnego RPC].

http://roy.gbiv.com/untangled/2008/rest-apis-must-be-hypertext-driven

Idea RESTful-URL jest w rzeczywistości naruszeniem REST, ponieważ serwer odpowiada za strukturę URL i powinien mieć swobodę decydowania, jak go użyć, aby uniknąć łączenia. Jeśli to dezorientuje, przeczytasz o znaczeniu samoodkrywania w projektowaniu API.

Użycie POST do tworzenia zasobów wiąże się z rozważaniami projektowymi, ponieważ POST nie jest idempotentny. Oznacza to, że kilkakrotne powtórzenie testu POST nie gwarantuje tego samego zachowania za każdym razem. To odstrasza ludzi od korzystania z PUT do tworzenia zasobów, kiedy nie powinni. Wiedzą, że to źle (POST jest dla CREATE), ale i tak to robią, ponieważ nie wiedzą, jak rozwiązać ten problem. Obawy te przejawiają się w następującej sytuacji:

  1. Klient POST przesyła nowy zasób do serwera.
  2. Serwer przetwarza żądanie i wysyła odpowiedź.
  3. Klient nigdy nie otrzymuje odpowiedzi.
  4. Serwer nie jest świadomy, że klient nie otrzymał odpowiedzi.
  5. Klient nie ma adresu URL zasobu (dlatego PUT nie jest opcją) i powtarza POST.
  6. POST nie jest idempotentny, a serwer…

Krok 6 to sytuacje, w których ludzie często mylą się co do tego, co robić. Jednak nie ma powodu, aby utworzyć kludge, aby rozwiązać ten problem. Zamiast tego można użyć protokołu HTTP, jak określono w RFC 2616, a serwer odpowiada:

10.4.10 409 Konflikt

Żądanie nie mogło zostać zakończone z powodu konfliktu z bieżącym stanem zasobu. Ten kod jest dozwolony tylko w sytuacjach, w których oczekuje się, że użytkownik będzie w stanie rozwiązać konflikt i ponownie przesłać żądanie. Treść odpowiedzi POWINNA zawierać wystarczającą liczbę

informacje dla użytkownika w celu rozpoznania źródła konfliktu. Idealnie, jednostka odpowiedzi zawierałaby wystarczającą ilość informacji dla użytkownika lub agenta użytkownika, aby rozwiązać problem; może to jednak nie być możliwe i nie jest wymagane.

Konflikty najczęściej występują w odpowiedzi na żądanie PUT. Na przykład, jeśli użyto wersjonowania, a obiekt PUT zawierał zmiany w zasobie, które powodują konflikt z zasobami dokonanymi przez wcześniejsze żądanie (strony trzeciej), serwer może użyć odpowiedzi 409, aby wskazać, że nie może zrealizować żądania . W takim przypadku jednostka odpowiedzi prawdopodobnie zawierałaby listę różnic między dwiema wersjami w formacie zdefiniowanym przez typ zawartości odpowiedzi.

Odpowiedzi z kodem statusu 409 Konflikt jest właściwym rozwiązaniem, ponieważ :

  • Wykonanie testu POST danych o identyfikatorze zgodnym z zasobem znajdującym się już w systemie jest „konfliktem z bieżącym stanem zasobu”.
  • Ponieważ ważną częścią klienta jest zrozumienie, że serwer ma zasoby i podjęcie odpowiednich działań. Jest to „sytuacja (sytuacje), w których oczekuje się, że użytkownik może rozwiązać konflikt i ponownie przesłać żądanie”.
  • Odpowiedź zawierająca adres URL zasobu o sprzecznym identyfikatorze i odpowiednie warunki wstępne dla zasobu zapewniłyby „wystarczającą ilość informacji dla użytkownika lub agenta użytkownika, aby rozwiązać problem”, co jest idealnym przypadkiem według RFC 2616.

Aktualizacja oparta na wydaniu RFC 7231 na Zastąpienie 2616

RFC 7231 ma zastąpić 2616, aw sekcji 4.3.3 opisano możliwą odpowiedź dla testu POST

Jeśli wynik przetwarzania testu POST byłby równoważny reprezentacji istniejącego zasobu, serwer źródłowy MOŻE przekierować agenta użytkownika do tego zasobu, wysyłając odpowiedź 303 (Zobacz Inne) z identyfikatorem istniejącego zasobu w polu Lokalizacja. Ma to tę zaletę, że zapewnia agentowi użytkownika identyfikator zasobu i przekazuje reprezentację za pomocą metody bardziej podatnej na współdzielone buforowanie, jednak kosztem dodatkowego żądania, jeśli agent użytkownika nie ma już buforowanej reprezentacji.

Może być kuszące, aby po prostu zwrócić wartość 303 w przypadku powtórzenia testu POST. Jednak prawda jest odwrotna. Zwrócenie wartości 303 miałoby sens tylko wtedy, gdy wiele żądań tworzenia (tworzenie różnych zasobów) zwróci tę samą treść. Przykładem może być „dziękuję za przesłanie wiadomości z prośbą”, której klient nie musi pobierać ponownie za każdym razem. RFC 7231 nadal utrzymuje w sekcji 4.2.2, że POST nie powinien być idempotentny i nadal utrzymuje, że POST powinien być używany do tworzenia.

Aby uzyskać więcej informacji na ten temat, przeczytaj ten artykuł .

Joshcodes
źródło
Czy odpowiedź na konflikt 409 byłaby odpowiednim kodem dla czegoś takiego jak próba utworzenia nowego konta z nazwą użytkownika, która już istnieje? Używam 409 do konfliktów między wersjami, ale po przeczytaniu twojej odpowiedzi zastanawiam się, czy nie należy jej używać do żadnych „duplikatów” żądań.
Eric B.,
@EricB. Tak, w opisywanej sytuacji „z powodu konfliktu z bieżącym stanem zasobu” operacja kończy się niepowodzeniem. Ponadto uzasadnione jest oczekiwanie, że użytkownik może rozwiązać konflikt, a treść wiadomości musi jedynie poinformować użytkownika, że ​​nazwa użytkownika już istnieje.
Joshcodes,
@Joshcodes, czy możesz powiedzieć więcej o procesie rozwiązywania konfliktów? W takim przypadku, jeśli nazwa użytkownika już istnieje, czy klient powinien pytać użytkownika końcowego o inną nazwę użytkownika? Co jeśli klient faktycznie próbuje użyć POST do zmiany nazwy użytkownika? Czy żądania PUT powinny być nadal używane do aktualizowania parametrów, podczas gdy POST służy do tworzenia obiektów, niezależnie od tego, czy jest to jeden, czy kilka? Dzięki.
BFar
@ BFar2, jeśli nazwa użytkownika już istnieje, klient powinien monitować użytkownika. Aby zmienić nazwę użytkownika, zakładając, że nazwa użytkownika jest częścią już utworzonego zasobu, który wymaga modyfikacji, PUT zostałby użyty, ponieważ masz rację, POST jest używany do tworzenia, a PUT do aktualizacji.
Joshcodes
pożądana jest także umiejętność wyjaśniania rzeczy za pomocą krótkiego i skutecznego języka
Junchen Liu
53

Podoba mi się ta rada z definicji PUT w RFC 2616 :

Podstawowa różnica między żądaniami POST i PUT znajduje odzwierciedlenie w innym znaczeniu URI żądania. Identyfikator URI w żądaniu POST identyfikuje zasób, który będzie obsługiwał zamknięty obiekt. Ten zasób może być procesem akceptującym dane, bramą do innego protokołu lub osobnym podmiotem, który przyjmuje adnotacje. W przeciwieństwie do tego, URI w żądaniu PUT identyfikuje encję zawartą w żądaniu - agent użytkownika wie, jaki jest URI, a serwer NIE MOŻE próbować zastosować żądania do jakiegoś innego zasobu.

Zastanawia się to nad inną radą, że PUT najlepiej jest stosować do zasobów, które już mają nazwę, a POST jest dobry do tworzenia nowego obiektu w ramach istniejącego zasobu (i pozwalania, aby serwer go nazwał).

Interpretuję to i wymagania idempotencji na Politechnice, co oznacza, że:

  • POST jest dobry do tworzenia nowych obiektów w kolekcji (a tworzenie nie musi być idempotentne)
  • PUT jest dobry do aktualizacji istniejących obiektów (a aktualizacja musi być idempotentna)
  • POST może być również wykorzystywany do nie idempotentnych aktualizacji istniejących obiektów (szczególnie do zmiany części obiektu bez określania całości - jeśli się nad tym zastanowić, utworzenie nowego członka kolekcji jest w rzeczywistości szczególnym przypadkiem tego rodzaju aktualizacja, z perspektywy kolekcji)
  • PUT może być również użyty do tworzenia, jeśli i tylko jeśli pozwolisz klientowi nazwać zasób. Ale ponieważ klienci REST nie powinni przyjmować założeń dotyczących struktury adresów URL, jest to mniej zgodne z założeniami.
metamatt
źródło
3
„POST może być również wykorzystywany do nie idempotentnych aktualizacji istniejących obiektów (szczególnie do zmiany części obiektu bez określania całości”. Do tego właśnie służy PATCH
Snuggs
48

W skrócie:

PUT jest idempotentny, w którym stan zasobu będzie taki sam, jeśli ta sama operacja zostanie wykonana jeden raz lub wiele razy.

POST nie jest idempotentny, w którym stan zasobu może się różnić, jeśli operacja jest wykonywana wiele razy w porównaniu do wykonywania jednorazowego.

Analogia z zapytaniem do bazy danych

PUT Możesz pomyśleć podobnie do „UPDATE STUDENT SET address =" abc ”where id =" 123 ";

POST Możesz pomyśleć o czymś takim jak „WSTAW DO STUDENTA (nazwa, adres) WARTOŚCI („ abc ”,„ xyzzz ”);

Identyfikator studenta jest generowany automatycznie.

W przypadku PUT, jeśli to samo zapytanie jest wykonywane wielokrotnie lub jeden raz, stan tabeli STUDENT pozostaje taki sam.

W przypadku testu POST, jeśli to samo zapytanie jest wykonywane wielokrotnie, wówczas w bazie danych tworzonych jest wiele rekordów Studentów, a stan bazy danych zmienia się przy każdym wykonaniu zapytania „INSERT”.

UWAGA: PUT potrzebuje lokalizacji zasobu (już-zasobu), na której musi nastąpić aktualizacja, podczas gdy POST tego nie wymaga. Dlatego intuicyjnie test POST służy do tworzenia nowego zasobu, podczas gdy PUT jest potrzebny do aktualizacji już istniejącego zasobu.

Niektóre mogą wymyślić, że aktualizacje mogą być wykonywane za pomocą POST. Nie ma twardej reguły, której użyć do aktualizacji lub której użyć do utworzenia. Ponownie są to konwencje i intuicyjnie jestem skłonny do powyższego rozumowania i podążam za nim.

Bharatj
źródło
6
dla PUT jest podobny do zapytania INSERT lub UPDATE
Eugen Konkov
1
faktycznie PUT Możesz pomyśleć podobnie do „UPDATE STUDENT SET adres =„ abc ”gdzie id =„ 123 ”; byłoby instrukcją dla PATCH.” UPDATE STUDENT SET adres = „abc”, name = „newname” gdzie id = ” 123 ”byłoby poprawną analogią dla PUT
mko
Put może również służyć do INSERT. Na przykład, jeśli serwer wykrył, że próbujesz przesłać ten sam plik wiele razy, spowodowałoby to, że twoje żądanie byłoby idempotentne. (Nie są przesyłane żadne nowe pliki).
kiwicomb123,
43

POST jest jak wysyłanie listu do skrzynki pocztowej lub wysyłanie wiadomości e-mail do kolejki e-mail. PUT jest jak umieszczenie przedmiotu w schowku lub miejscu na półce (ma znany adres).

Dzięki POST wysyłasz pocztę na adres KOLEJKI lub KOLEKCJI. Dzięki PUT podajesz adres POZYCJI.

PUT jest idempotentny. Możesz wysłać zapytanie 100 razy i to nie będzie miało znaczenia. POST nie jest idempotentny. Jeśli wyślesz zapytanie 100 razy, otrzymasz 100 e-maili lub 100 listów w swojej skrzynce pocztowej.

Ogólna zasada: jeśli znasz identyfikator lub nazwę przedmiotu, użyj PUT. Jeśli chcesz, aby identyfikator lub nazwa elementu były przypisywane przez stronę odbierającą, użyj POST.

POST a PUT

Homer6
źródło
1
Nie, PUT oznacza, że ​​znasz adres URL. Jeśli znasz tylko identyfikator, POST z tym identyfikatorem, aby uzyskać adres URL.
Joshcodes
6
Identyfikator jest częścią adresu URL, więc tak, użyj PUT, jeśli znasz adres URL (który zawiera identyfikator).
Homer6,
Nie, adres URL jest określany przez serwer, a identyfikator niekoniecznie jest częścią adresu URL. Roy Fielding powiedziałby ci to samo lub możesz po prostu przeczytać jego pracę magisterską .
Joshcodes
@Joshcodes, czy to zakłada REST? W architekturze RESTful identyfikator elementu jest zdecydowanie częścią adresu URL, jak w: / people / 123. Podoba mi się ta strona dla REST: microformats.org/wiki/rest/urls
Beez
1
@Beez link mircoformats sugeruje, że serwery mogą porządkować swoje adresy URL, ale serwer określa adres URL. Klient prawie nigdy. Zobacz moją odpowiedź lub powiązany artykuł, jeśli tego nie rozumiesz.
Joshcodes
39

Nowa odpowiedź (teraz, gdy lepiej rozumiem REST):

PUT jest jedynie stwierdzeniem, jakiej zawartości usługa powinna odtąd używać do renderowania reprezentacji zasobu zidentyfikowanego przez klienta; POST to stwierdzenie, jakie treści powinna odtąd zawierać usługa (być może zduplikowana), ale od serwera zależy, jak ją zidentyfikować.

PUT x(jeśli xidentyfikuje zasób ): „Zastąp zawartość zasobu wskazanego przez xmoją zawartością”.

PUT x(jeśli xnie identyfikuje zasobu): „Utwórz nowy zasób zawierający moją treść i użyj go xdo zidentyfikowania”.

POST x: „Przechowuj moją treść i podaj identyfikator, którego mogę użyć do zidentyfikowania zasobu (starego lub nowego) zawierającego tę treść (być może zmieszanego z inną treścią). Wymieniony zasób powinien być identyczny lub podporządkowany temu, który xidentyfikuje”. „ R «a źródło jest podporządkowany x »źródło S” jest zazwyczaj, ale niekoniecznie realizowane poprzez pręd podścieżkę z X (na przykład x = /fooi y = /foo/bar) oraz modyfikację reprezentacji (y) x zasobów „S odzwierciedla istnienie nowego zasobu, np. z hiperłączem do yzasoby i niektóre metadane. Tylko ta ostatnia jest naprawdę niezbędna do dobrego zaprojektowania, ponieważ adresy URL są nieprzejrzyste w REST - powinieneś użyć hipermedii zamiast konstrukcji adresu URL po stronie klienta, aby przejść przez usługę.

W REST nie ma czegoś takiego jak zasób zawierający „treść”. Odnoszę się do „treści” do danych, które usługa wykorzystuje do spójnego renderowania reprezentacji. Zwykle składa się z niektórych powiązanych wierszy w bazie danych lub pliku (np. Plik obrazu). Usługa polega na przekształceniu treści użytkownika w coś, z czego usługa może korzystać, np. Przekształcenie ładunku JSON w instrukcje SQL.

Oryginalna odpowiedź (może być łatwiejsza do odczytania) :

PUT /something(jeśli /somethingjuż istnieje): „Weź wszystko, co masz /somethingi zamień to, co ci daję”.

PUT /something(jeśli jeszcze /somethingnie istnieje): „Weź to, co ci daję i połóż to /something”.

POST /something: „Weź to, co ci daję, i umieść to w dowolnym miejscu, pod /somethingwarunkiem, że podasz mi adres URL, gdy skończysz”.

Jordania
źródło
Ale w jaki sposób możesz użyć PUT do utworzenia nowego zasobu, jeśli nie istnieje, podczas gdy twoja metoda generowania identyfikatora jest w trybie Auto Increment? Zwykle ORM automatycznie generuje dla Ciebie identyfikator, na przykład tak, jak chcesz, aby znajdował się w POST. Czy to oznacza, że ​​jeśli chcesz zaimplementować PUT we właściwy sposób, musisz zmienić automatyczne generowanie identyfikatora? Jest to niewygodne, jeśli odpowiedź brzmi „tak”.
Roni Axelrad
1
@RoniAxelrad: PUT jest jak instrukcja „INSERT OR UPDATE” bazy danych, w której umieszczasz klucz w instrukcji, więc ma zastosowanie tylko wtedy, gdy nie możesz zagwarantować żadnych kolizji. na przykład. Twoja domena ma „naturalny klucz” lub korzystasz z GUID. POST jest jak wstawianie do tabeli za pomocą klucza automatycznego zwiększania. Baza danych musi powiedzieć, jaki identyfikator otrzymał po wstawieniu. Pamiętaj, że „WSTAW LUB AKTUALIZACJA” zastąpi wszelkie poprzednie dane, jeśli takie istniały.
Nigel Thorne,
@NigelThorne Dzięki za odpowiedź. Więc jeśli na przykład próbuję PUT book 10 o identyfikatorze URI: PUT books / 10. Jeśli książka o id 10 nie istnieje, powinienem utworzyć książkę o id 10, prawda? ale nie mogę kontrolować licznika identyfikatora tworzenia, ponieważ jest to automatyczny przyrost. co powinienem zrobić w tej sytuacji?
Roni Axelrad
1
@ RoniAxelrad REST PUT do identyfikatora, który nie istnieje, jest żądaniem do serwera utworzenia zasobu. Serwer nadal decyduje, czy chce na to pozwolić. Serwer jest odpowiedzialny. Może odpowiedzieć „Nie, nie zamierzam tego robić”. Już to robisz, jeśli użytkownik nie ma wystarczających uprawnień ... itd. Serwer może powiedzieć „Nie”. REST to konwencja, która pozwala nam zdefiniować znaczenie różnych rodzajów żądań ... Twój serwer decyduje, co zrobić z tymi żądaniami w oparciu o logikę biznesową :) Nawet jeśli powie „nie”, nadal śledzi REST :)
Nigel Thorne
38

Krótka odpowiedź:

Prosta zasada: użyj POST do utworzenia, użyj PUT do aktualizacji.

Długa odpowiedź:

POCZTA:

  • POST służy do wysyłania danych do serwera.
  • Przydatne, gdy adres URL zasobu jest nieznany

POŁOŻYĆ:

  • PUT służy do przesyłania stanu na serwer
  • Przydatne, gdy znany jest adres URL zasobu

Dłuższa odpowiedź:

Aby to zrozumieć, musimy zapytać, dlaczego PUT był wymagany, jakie problemy PUT próbował rozwiązać, czego POST nie mógł.

Z punktu widzenia architektury REST żadna nie ma znaczenia. Moglibyśmy również żyć bez PUT. Ale z punktu widzenia dewelopera klienta znacznie ułatwiło mu to życie.

Przed PUT klienci nie mogli bezpośrednio znać adresu URL wygenerowanego przez serwer ani tego, czy wszystko wygenerowało, czy też dane do wysłania na serwer są już zaktualizowane, czy nie. PUT uwolnił twórcę wszystkich tych bólów głowy. PUT jest idempotentny, PUT obsługuje warunki wyścigu, a PUT pozwala klientowi wybrać adres URL.

ishandutta2007
źródło
3
Twoja krótka odpowiedź może być BARDZO błędna. HTTP PUT może być powtarzane przez proxy HTTP. I tak, jeśli PUT faktycznie wykonuje WSTAWIENIE SQL, może się nie powieść po raz drugi, co oznacza, że ​​zwróci inny wynik, a więc nie będzie IDEMPOTENT (co jest różnicą między PUT a POST)
Kamil Tomšík
36

Ruby on Rails 4.0 użyje metody „PATCH” zamiast PUT, aby dokonać częściowych aktualizacji.

RFC 5789 mówi o PATCH (od 1995):

Konieczna jest nowa metoda w celu poprawy interoperacyjności i zapobiegania błędom. Metoda PUT jest już zdefiniowana w celu zastąpienia zasobu kompletnym nowym ciałem i nie można jej ponownie użyć do dokonania częściowych zmian. W przeciwnym razie serwery proxy i pamięci podręczne, a nawet klienci i serwery, mogą się mylić co do wyniku operacji. POST jest już używany, ale bez szerokiej interoperacyjności (po pierwsze, nie ma standardowego sposobu na wykrycie obsługi formatu łatki). PATCH został wspomniany we wcześniejszych specyfikacjach HTTP, ale nie do końca zdefiniowany.

Edge Rails: PATCH to nowa podstawowa metoda HTTP do aktualizacji ” - wyjaśnia.

germanlinux
źródło
27

Ryzykując powtórzenie tego, co już powiedziano, wydaje się ważne, aby pamiętać, że PUT sugeruje, że klient kontroluje, jaki będzie adres URL podczas tworzenia zasobu. Tak więc część wyboru między PUT a POST będzie polegać na tym, na ile możesz ufać klientowi, że dostarczy prawidłowy, znormalizowany URL, który jest spójny z dowolnym schematem URL.

Jeśli nie możesz w pełni ufać klientowi, że zrobi to dobrze, lepiej byłoby użyć POST do utworzenia nowego elementu, a następnie odesłać adres URL z powrotem do klienta w odpowiedzi.

złodziej patelni
źródło
2
Trochę się spóźniłem - ale ktoś, kto powiedział coś podobnego na innej stronie, kazał mi kliknąć. Jeśli tworzysz zasób i używasz automatycznie zwiększanego identyfikatora jako jego „identyfikatora” zamiast nazwy przypisanej przez użytkownika, powinien to być test POST.
Ixmatus
2
To nie jest całkiem w porządku - PUT można jeszcze utworzyć zasób, odwołując się do niego o nazwie niekanonicznej, tak długo, jak w odpowiedzi, powraca Serwer Locationnagłówka, który ma zawierać kanoniczną nazwę zasobu.
Eter
1
@Joshcodes nie zapominaj, że możesz mieć wiele identyfikatorów URI odnoszących się do tego samego zasobu podstawowego. Więc to, co Ether powiedział, to dobra rada, klient może umieścić adres URL (który może być bardziej semantyczny PUT /X-files/series/4/episodes/max), a serwer odpowiada URI, który zapewnia krótki kanoniczny unikalny link do tego nowego zasobu (tj. /X-Ffiles/episodes/91)
thecoshman
@ thecoshman problem polega na tym, że struktura adresu URL nie należy do klienta. Czytanie o samodzielnym odkrywaniu (także części REST) ​​może pomóc to wyjaśnić.
Joshcodes,
@Joshcodes, zgodnie z tą logiką, klient nigdy nie powinien używać PUT do tworzenia, ponieważ nie powinien zajmować się podaniem adresu URL. No cóż ... chyba że serwer podał adres URL do PUT, jeśli klient chce go umieścić ... coś w rodzaju „PUT / comments / new”, a serwer może odpowiedzieć „204 / comments / 234532”, ale wydaje się to trochę RPC do mnie, klient powinien po prostu POST
wysłać
24

W bardzo prosty sposób biorę przykład osi czasu na Facebooku.

Przypadek 1: Gdy publikujesz coś na osi czasu, jest to nowy nowy wpis. Dlatego w tym przypadku używają metody POST, ponieważ metoda POST nie jest idempotentna.

Przypadek 2: Jeśli Twój przyjaciel skomentuje Twój post po raz pierwszy, spowoduje to również utworzenie nowego wpisu w bazie danych, dzięki czemu zastosowana metoda POST.

Przypadek 3: Jeśli twój przyjaciel edytuje swój komentarz, w tym przypadku miał identyfikator komentarza, więc zaktualizuje istniejący komentarz zamiast tworzyć nowy wpis w bazie danych. Dlatego do tego typu operacji używaj metody PUT, ponieważ jest idempotentna. *

W jednym wierszu użyj POST, aby dodać nowy wpis do bazy danych, i PUT, aby zaktualizować coś w bazie danych.

UniCoder
źródło
4
Jeśli komentarz jest obiektem o właściwościach takich jak identyfikator użytkownika, data utworzenia, wiadomość komentarza itp., A podczas edycji aktualizowana jest tylko wiadomość komentarza, PATCH należy tutaj wykonać?
Habeeb Perwad
PUT jest używany przez FB do aktualizacji komentarza, ponieważ istniejący zasób jest aktualizowany, i to właśnie robi PUT (aktualizuje zasób). PUT bywa idempotentny, w przeciwieństwie do POST. Czasownik idempotentny HTTP wpływa na obsługę błędów, ale nie narzuca użycia. Zobacz moją odpowiedź w celu uzyskania bardziej szczegółowych wyjaśnień: stackoverflow.com/questions/630453/put-vs-post-in-rest/…
Joshcodes
21

Najważniejszą kwestią jest niezawodność . W przypadku zagubienia komunikatu POST stan systemu jest niezdefiniowany. Automatyczne odzyskiwanie jest niemożliwe. W przypadku komunikatów PUT stan jest niezdefiniowany tylko do pierwszej pomyślnej ponownej próby.

Na przykład tworzenie transakcji kartami kredytowymi za pomocą POST może nie być dobrym pomysłem.

Jeśli zdarzy się, że masz automatycznie wygenerowane URI w twoim zasobie, możesz nadal używać PUT, przekazując wygenerowany URI (wskazując na pusty zasób) do klienta.

Inne uwagi:

  • POST unieważnia buforowane kopie całego zawierającego zasoby (lepsza spójność)
  • Odpowiedzi PUT nie są buforowane, podczas gdy odpowiedzi POST są (Wymagaj lokalizacji treści i wygaśnięcia)
  • PUT jest mniej obsługiwany np. Przez Java ME, starsze przeglądarki, zapory ogniowe
Hans Malherbe
źródło
To jest niepoprawne. W przypadku testu POST stan jest również niezdefiniowany tylko do pierwszej pomyślnej ponownej próby. Następnie albo serwer akceptuje test POST (wiadomość nigdy nie dotarła), generuje konflikt 409 dla duplikatu identyfikatora (wiadomość dotarła, odpowiedź została utracona) lub inną prawidłową odpowiedź.
Joshcodes
Ogólnie rzecz biorąc, użytkownik nie byłby w stanie bezpiecznie bezpiecznie ponowić operacji POST, ponieważ operacja POST nie daje żadnej gwarancji, że dwie operacje będą miały taki sam efekt jak jedna. Termin „ID” nie ma nic wspólnego z HTTP. Identyfikator URI identyfikuje zasób.
Hans Malherbe
Useragent może „bezpiecznie” ponowić operację POST tyle razy, ile chce. Otrzyma tylko błąd duplikatu identyfikatora (zakładając, że zasób ma identyfikator) lub błąd duplikatu danych (zakładając, że to problem, a zasób nie ma identyfikatorów).
Joshcodes
Uderzenie głową o ścianę. HTTP nie ma rozwiązania problemu niezawodności i nie jest to dobrze zrozumiałe, mało dyskutowane i po prostu nie pokrywane w zdecydowanej większości aplikacji internetowych. @Joshcodes Mam odpowiedź na to pytanie. Zasadniczo zgadzam się z Hansem. Jest pewien problem.
bbsimonbb
@bbsimonbb, HTTP ma solidny i dobrze udokumentowany zestaw odpowiedzi na błędy. Moja odpowiedź na to pytanie ( stackoverflow.com/questions/630453/put-vs-post-in-rest/... ) dotyczy sposobu używania protokołu HTTP zgodnie ze specyfikacją w celu osiągnięcia spójności.
Joshcodes,
17

Czytelnicy, którzy nie znają tego tematu, będą poruszeni niekończącą się dyskusją na temat tego, co powinieneś zrobić, oraz względnym brakiem lekcji z doświadczenia. Fakt, że REST jest „preferowany” w stosunku do SOAP, jest, jak sądzę, uczeniem się na wysokim poziomie z doświadczenia, ale dobroć musieliśmy stamtąd rozwijać? Jest rok 2016. Praca doktorska Roya miała miejsce w 2000 roku. Co opracowaliśmy? Fajnie było? Czy łatwo było się zintegrować? Wspierać? Czy poradzi sobie ze wzrostem liczby smartfonów i niestabilnych połączeń mobilnych?

Według ME rzeczywiste sieci są zawodne. Upłynął limit czasu żądania. Połączenia są resetowane. Sieci przestają działać na kilka godzin lub dni na raz. Pociągi jeżdżą do tuneli z użytkownikami mobilnymi na pokładzie. W przypadku każdej prośby (co czasami potwierdzane w całej tej dyskusji) prośba może wpaść do wody na swojej drodze lub odpowiedź może spaść do wody w drodze powrotnej. W tych warunkach wysyłanie żądań PUT, POST i DELETE bezpośrednio do zasobów materialnych zawsze wydawało mi się trochę brutalne i naiwne.

HTTP nie robi nic, aby zapewnić niezawodne zakończenie odpowiedzi na żądanie, i jest w porządku, ponieważ jest to właściwie zadanie aplikacji obsługujących sieć. Opracowując taką aplikację, możesz przeskakiwać przez obręcze, aby użyć PUT zamiast POST, a następnie więcej obręczy, aby dać pewien rodzaj błędu na serwerze, jeśli wykryjesz duplikaty żądań. Po powrocie do klienta musisz przeskoczyć przez obręcze, aby zinterpretować te błędy, ponownie pobrać, zweryfikować ponownie i opublikować ponownie.

Lub możesz to zrobić : rozważ swoje niebezpieczne żądania jako efemeryczne zasoby dla pojedynczego użytkownika (nazwijmy je akcjami). Klienci żądają nowej „akcji” w odniesieniu do zasobu merytorycznego z pustym testem POST do zasobu. POST będzie używany tylko do tego. Po bezpiecznym posiadaniu identyfikatora URI świeżo wybitej akcji klient umieszcza niebezpieczne żądanie do identyfikatora URI akcji, a nie zasobu docelowego . Rozwiązanie akcji i aktualizacja „prawdziwego” zasobu jest właściwie zadaniem twojego API i jest tutaj oddzielona od niewiarygodnej sieci.

Serwer zajmuje się biznesem, zwraca odpowiedź i przechowuje ją w stosunku do uzgodnionego URI akcji . Jeśli coś pójdzie nie tak, klient powtarza żądanie (naturalne zachowanie!), A jeśli serwer już to widział, powtarza zapisaną odpowiedź i nic więcej nie robi .

Szybko zauważysz podobieństwo dzięki obietnicom: tworzymy i zwracamy symbol zastępczy wyniku, zanim cokolwiek zrobisz. Podobnie jak obietnica, akcja może zakończyć się sukcesem lub porażką, ale jej wynik można wielokrotnie pobrać.

Co najlepsze, dajemy aplikacjom wysyłającym i odbierającym możliwość połączenia jednoznacznie zidentyfikowanej akcji z unikalnością w ich odpowiednich środowiskach. I możemy zacząć żądać i egzekwować !, odpowiedzialne zachowanie od klientów: powtarzaj swoje prośby tak, jak chcesz, ale nie generuj nowej akcji, dopóki nie uzyskasz ostatecznego wyniku z istniejącej.

Jako takie znikają liczne kolczaste problemy. Powtarzane żądania wstawiania nie utworzą duplikatów i nie tworzymy prawdziwego zasobu, dopóki nie będziemy w posiadaniu danych. (kolumny bazy danych mogą nie być zerowalne). Powtarzane żądania aktualizacji nie trafią w niezgodne stany i nie zastąpią kolejnych zmian. Klienci mogą (ponownie) pobierać i bezproblemowo przetwarzać oryginalne potwierdzenie z dowolnego powodu (klient się zawiesił, brakowało odpowiedzi itp.).

Kolejne żądania usunięcia mogą wyświetlać i przetwarzać oryginalne potwierdzenie, nie popełniając błędu 404. Jeśli zajmie to więcej czasu niż oczekiwano, możemy tymczasowo odpowiedzieć i mamy miejsce, w którym klient może sprawdzić ostateczny wynik. Najładniejszą częścią tego wzoru jest jego właściwość Kung-Fu (Panda). Bierzemy słabość, skłonność klientów do powtarzania zapytania za każdym razem, gdy nie rozumieją odpowiedzi, i przekształcania go w siłę :-)

Zanim powiesz mi, że to nie jest RESTful, proszę rozważyć liczne sposoby przestrzegania zasad REST. Klienci nie konstruują adresów URL. Interfejs API pozostaje wykrywalny, choć z niewielką zmianą semantyki. Czasowniki HTTP są używane odpowiednio. Jeśli uważasz, że jest to ogromna zmiana do wdrożenia, z doświadczenia mogę powiedzieć, że tak nie jest.

Jeśli uważasz, że będziesz mieć do przechowywania ogromne ilości danych, porozmawiajmy o objętościach: typowe potwierdzenie aktualizacji to ułamek kilobajta. HTTP daje obecnie minutę lub dwie na ostateczną odpowiedź. Nawet jeśli przechowujesz działania tylko przez tydzień, klienci mają dużą szansę na nadrobienie zaległości. Jeśli masz bardzo duże woluminy, możesz potrzebować dedykowanego magazynu wartości klucza zgodnego z kwasem lub rozwiązania w pamięci.

bbsimonbb
źródło
1
Czy przechowywanie odpowiedzi nie będzie przypominało prowadzenia sesji? Co spowodowałoby problemy ze skalowaniem (poziomym).
Saurabh Harwande
17

Oprócz różnic sugerowanych przez innych, chcę dodać jeszcze jeden.

W metodzie POST możesz wysyłać parametry ciałaform-data

W metodzie PUT musisz wysłać parametry ciałax-www-form-urlencoded

nagłówek Content-Type:application/x-www-form-urlencoded

Zgodnie z tym nie można wysyłać plików ani danych wieloczęściowych metodą PUT

EDYTOWAĆ

Typ zawartości „application / x-www-form-urlencoded” jest nieefektywny w przypadku wysyłania dużych ilości danych binarnych lub tekstu zawierającego znaki spoza ASCII. Do przesyłania formularzy zawierających pliki, dane inne niż ASCII i dane binarne należy używać typu treści „multipart / form-data”.

Co oznacza, że ​​musisz przesłać

pliki, dane inne niż ASCII i dane binarne

powinieneś użyć metody POST

Rohit Dhiman
źródło
3
Dlaczego to nie zostało ocenione? Jeśli to prawda, to jest to krytyczne rozróżnienie, prawda?
Iofacture
2
Napotkałem to podczas wdrażania interfejsu API do aktualizacji profilu, który obejmuje przesyłanie zdjęć z profilu użytkownika. Następnie przetestowałem go z listonoszem, Ajax, PHP curl i laravel 5.6 jako backend.
Rohit Dhiman
14

Wydaje się, że zawsze istnieje pewne zamieszanie co do tego, kiedy używać metody HTTP POST w porównaniu z metodą HTTP PUT dla usług REST. Większość programistów spróbuje powiązać operacje CRUD bezpośrednio z metodami HTTP. Będę argumentować, że nie jest to poprawne i nie można po prostu powiązać koncepcji CRUD z metodami HTTP. To jest:

Create => HTTP PUT
Retrieve => HTTP GET
Update => HTTP POST
Delete => HTTP DELETE

Prawdą jest, że R (etrieve) i D (elete) operacji CRUD można odwzorować bezpośrednio na metody HTTP odpowiednio GET i DELETE. Jednak zamieszanie polega na operacjach C (reate) i U (update). W niektórych przypadkach można użyć PUT do utworzenia, podczas gdy w innych przypadkach wymagany będzie test POST. Niejednoznaczność polega na definicji metody HTTP PUT w porównaniu z metodą HTTP POST.

Zgodnie ze specyfikacjami HTTP 1.1 metody GET, HEAD, DELETE i PUT muszą być idempotentne, a metoda POST nie jest idempotentna. To znaczy, że operacja jest idempotentna, jeśli można ją wykonać na zasobie raz lub wiele razy i zawsze zwraca ten sam stan tego zasobu. Natomiast nie idempotentna operacja może zwrócić zmodyfikowany stan zasobu z jednego żądania do drugiego. Dlatego w nie idempotentnej operacji nie ma gwarancji, że ktoś otrzyma taki sam stan zasobu.

Opierając się na powyższej idempotentnej definicji, moje podejście do używania metody HTTP PUT w porównaniu do metody HTTP POST dla usług REST jest następujące: Użyj metody HTTP PUT, gdy:

The client includes all aspect of the resource including the unique identifier to uniquely identify the resource. Example: creating a new employee.
The client provides all the information for a resource to be able to modify that resource.This implies that the server side does not update any aspect of the resource (such as an update date).

W obu przypadkach operacje te można wykonać wiele razy z tymi samymi wynikami. Oznacza to, że zasób nie zostanie zmieniony poprzez żądanie operacji więcej niż raz. Stąd prawdziwa idempotentna operacja. Użyj metody HTTP POST, gdy:

The server will provide some information concerning the newly created resource. For example, take a logging system. A new entry in the log will most likely have a numbering scheme which is determined on the server side. Upon creating a new log entry, the new sequence number will be determined by the server and not by the client.
On a modification of a resource, the server will provide such information as a resource state or an update date. Again in this case not all information was provided by the client and the resource will be changing from one modification request to the next. Hence a non idempotent operation.

Wniosek

Nie należy bezpośrednio korelować i mapować operacji CRUD na metody HTTP dla usług REST. Zastosowanie metody HTTP PUT w porównaniu z metodą HTTP POST powinno opierać się na idempotentnym aspekcie tej operacji. Oznacza to, że jeśli operacja jest idempotentna, użyj metody HTTP PUT. Jeśli operacja nie jest idempotentna, użyj metody HTTP POST.

Burhan
źródło
2
Aktualizacja => POST HTTP: POST nie jest przeznaczony do aktualizacji
Premraj 30.01.2016
@premraj Przyjąłeś, że Burhan mówi ci, abyś tego nie robił; mianowicie łączysz CRUD, REST i HTTP. Jeśli czytasz RFC 7231, gdzie te rzeczy są zdefiniowane, przekonasz się, że w protokole HTTP definicja POST z pewnością pozwala na aktualizację. Tylko ograniczenia REST mówią inaczej.
IAM_AL_X
13

serwer źródłowy może utworzyć zasób z tym identyfikatorem URI

Więc używasz POST i prawdopodobnie, ale niekoniecznie PUT do tworzenia zasobów. Nie musisz wspierać obu. Dla mnie POST jest całkowicie wystarczający. Jest to więc decyzja projektowa.

Jak wspomniałem w swoim cytacie, używasz PUT do tworzenia, że ​​do IRI nie jest przypisany żaden zasób, a mimo to chcesz utworzyć zasób. Na przykład PUT /users/123/passwordzwykle zastępuje stare hasło nowym, ale można go użyć do utworzenia hasła, jeśli jeszcze nie istnieje (na przykład przez świeżo zarejestrowanych użytkowników lub przez przywrócenie zablokowanych użytkowników).

inf3rno
źródło
Myślę, że udało ci się podać jeden z niewielu dobrych przykładów użycia PUT, dobra robota.
thecoshman
12

Wyląduję z następującymi:

PUT odnosi się do zasobu identyfikowanego przez URI. W takim przypadku aktualizujesz go. Jest to część trzech czasowników odnoszących się do zasobów - usuń i zdobądź pozostałe dwa.

POST jest zasadniczo komunikatem o dowolnej formie, którego znaczenie definiuje się jako „poza pasmem”. Jeśli wiadomość można interpretować jako dodawanie zasobu do katalogu, byłoby to w porządku, ale w zasadzie musisz zrozumieć wysyłaną wiadomość (publikowanie), aby wiedzieć, co się stanie z zasobem.


Ponieważ PUT oraz GET i DELETE odnoszą się do zasobu, z definicji są również idempotentne.

POST może wykonywać pozostałe trzy funkcje, ale wówczas semantyka żądania zostanie utracona na pośrednikach, takich jak pamięci podręczne i serwery proxy. Dotyczy to również zapewnienia bezpieczeństwa zasobu, ponieważ identyfikator URI postu niekoniecznie wskazuje zasób, do którego się stosuje (może jednak).

PUT nie musi być kreacją; usługa może popełnić błąd, jeśli zasób nie został jeszcze utworzony, ale w przeciwnym razie zaktualizuj go. Lub odwrotnie - może tworzyć zasób, ale nie zezwalać na aktualizacje. Jedyną rzeczą wymaganą w PUT jest to, że wskazuje on na konkretny zasób, a jego ładunek stanowi reprezentacja tego zasobu. Udany test PUT oznacza (z wyłączeniem interferencji), że GET odzyska ten sam zasób.


Edycja: Jeszcze jedno - PUT może utworzyć, ale jeśli tak, to identyfikator musi być identyfikatorem naturalnym - AKA to adres e-mail. W ten sposób, kiedy wkładasz dwa razy, drugie wprowadzenie jest aktualizacją pierwszego. To czyni go idempotentnym .

Jeśli identyfikator zostanie wygenerowany (na przykład nowy identyfikator pracownika), wówczas drugi PUT z tym samym adresem URL utworzy nowy rekord, co narusza zasadę idempotent. W tym przypadku czasownikiem będzie POST, a komunikat (nie zasób) miałby utworzyć zasób przy użyciu wartości zdefiniowanych w tym komunikacie.

Gerard ONeill
źródło
9

Semantyka powinna być inna, pod tym względem, że „PUT”, podobnie jak „GET”, ma być idempotentny - co oznacza, że ​​możesz dokładnie tyle samo żądań PUT, a wynik będzie taki, jakbyś wykonał je tylko raz.

Opiszę konwencje, które moim zdaniem są najczęściej stosowane i są najbardziej przydatne:

Kiedy umieszczasz zasób pod określonym adresem URL, dzieje się tak, że powinien on zostać zapisany pod tym adresem URL lub coś w tym stylu.

Podczas wysyłania do zasobu pod określonym adresem URL często publikujesz powiązaną informację pod tym adresem URL. Oznacza to, że zasób pod adresem URL już istnieje.

Na przykład, jeśli chcesz utworzyć nowy strumień, możesz umieścić go pod jakimś adresem URL. Ale jeśli chcesz wysłać wiadomość do istniejącego strumienia, możesz wysłać wiadomość do jej adresu URL.

Jeśli chodzi o modyfikowanie właściwości strumienia, możesz to zrobić za pomocą PUT lub POST. Zasadniczo używaj „PUT” tylko wtedy, gdy operacja jest idempotentna - w przeciwnym razie użyj POST.

Należy jednak pamiętać, że nie wszystkie współczesne przeglądarki obsługują czasowniki HTTP inne niż GET lub POST.

Gregory Magarshak
źródło
To, co opisujesz POST, to tak naprawdę to, jak PATCH powinien się zachowywać. POST ma oznaczać coś bardziej podobnego do „dołączania”, jak w „wysyłaniu na listę mailingową”.
Alexander Torstling
8

Przez większość czasu będziesz używać ich w następujący sposób:

  • POST zasób w kolekcji
  • PUT zasób określony przez collection /: id

Na przykład:

  • POST / przedmioty
  • PUT / items / 1234

W obu przypadkach treść żądania zawiera dane dotyczące zasobu, który ma zostać utworzony lub zaktualizowany. Z nazw tras powinno być oczywiste, że test POST nie jest idempotentny (jeśli wywołasz go 3 razy, utworzą 3 obiekty), ale PUT jest idempotentny (jeśli wywołasz go 3 razy, wynik będzie taki sam). PUT jest często używany do operacji „upsert” (tworzenie lub aktualizacja), ale zawsze możesz zwrócić błąd 404, jeśli chcesz go użyć tylko do modyfikacji.

Zauważ, że POST „tworzy” nowy element w kolekcji, a PUT „zastępuje” element pod danym adresem URL, ale bardzo powszechną praktyką jest stosowanie PUT do częściowych modyfikacji, tj. Używanie go tylko do aktualizacji istniejących zasobów i modyfikuj tylko zawarte pola w treści (ignorując inne pola). Jest to technicznie niepoprawne, jeśli chcesz być purystą REST, PUT powinien zastąpić cały zasób i powinieneś użyć PATCH do częściowej aktualizacji. Osobiście nie dbam o to, o ile zachowanie jest jasne i spójne we wszystkich punktach końcowych interfejsu API.

Pamiętaj, że REST to zestaw konwencji i wytycznych, które upraszczają interfejs API. Jeśli skończysz na skomplikowanym obejściu, aby tylko zaznaczyć pole „RESTfull”, to pokonujesz cel;)

tothemario
źródło
7

Chociaż istnieje prawdopodobnie agnostyczny sposób ich opisania, wydaje się, że jest sprzeczny z różnymi stwierdzeniami z odpowiedzi na strony internetowe.

Bądźmy tutaj bardzo klarowni i bezpośredni. Jeśli jesteś programistą .NET pracującym z interfejsem API sieci Web, fakty są (z dokumentacji interfejsu API Microsoft), http://www.asp.net/web-api/overview/creating-web-apis/creating-a-web -api-that-wspiera-operacje-crud :

1. PUT = UPDATE (/api/products/id)
2. MCSD Exams 2014 -  UPDATE = PUT, there are **NO** multiple answers for that question period.

Jasne, że „możesz” użyć „POST” do aktualizacji, ale postępuj zgodnie z konwencjami określonymi dla danego frameworka. W moim przypadku jest to .NET / Web API, więc PUT jest na UPDATE, nie ma debaty.

Mam nadzieję, że pomoże to wszystkim programistom Microsoft, którzy czytają wszystkie komentarze z linkami do witryn Amazon i Sun / Java.

Tom Stickel
źródło
7

Oto prosta zasada:

PUT do adresu URL należy użyć do aktualizacji lub utworzenia zasobu, który może znajdować się pod tym adresem URL.

POST do adresu URL należy użyć do aktualizacji lub utworzenia zasobu, który znajduje się pod innym („podrzędnym”) adresem URL lub którego nie można zlokalizować przez HTTP.

Adam Griffiths
źródło
1
PUT nie jest do aktualizacji, jest do zastąpienia, pamiętaj, że aby utworzyć, nic nie zastępujesz czymś. POST absolutnie nie jest przeznaczony do aktualizacji w żadnej formie.
thecoshman
2
Czy specyfikacja http tak mówi? A może opierasz swój komentarz na czymś innym?
Adam Griffiths,
To po prostu zdrowy rozsądek, jak coś aktualizować, jeśli nie wiesz, co aktualizujesz? POST służy do tworzenia nowego zasobu.
thecoshman
2
thecoshman - nadużywasz tutaj semantyki - zamiennik może być aktualizacją, jeśli jest to ten sam zasób z kilkoma różnicami. Zastąpienie jest ważne tylko dla put, jeśli zamiana jest używana do zmiany tego samego zasobu. Zastąpienie nowym i innym zasobem jest nieprawidłowe (usunąć stary i dodać nowy?), Szczególnie jeśli „nowy” zasób nie ma naturalnego identyfikatora. POST, OTOH, to coś, co można tworzyć, aktualizować, zamieniać i usuwać - korzystanie z postów zależy od tego, czy istnieje komunikat do interpretacji, na przykład „zastosuj zniżkę”, który może, ale nie musi, zmienić zasób w zależności od logika.
Gerard ONeill
Co do drugiego komentarza - co powiesz na „zdobycie” zasobu, zmodyfikowanie pól, które musisz, a następnie odłożenie go z powrotem? A może zasób pochodzi z innego źródła, ale korzysta z naturalnego identyfikatora (zewnętrznego identyfikatora) - put w naturalny sposób zaktualizuje zasób pod adresem URL po zmianie oryginalnych danych.
Gerard ONeill
6

Jeśli znasz operacje na bazie danych, istnieją

  1. Wybierz
  2. Wstawić
  3. Aktualizacja
  4. Usunąć
  5. Scal (zaktualizuj, jeśli już istnieje, w przeciwnym razie wstaw)

Używam PUTdo scalania i aktualizuję podobne operacje i używam POSTdo wstawiania.

Rajan
źródło
5

W praktyce POST działa dobrze przy tworzeniu zasobów. Adres URL nowo utworzonego zasobu powinien zostać zwrócony w nagłówku odpowiedzi Lokalizacja. PUT powinien być używany do całkowitej aktualizacji zasobu. Proszę zrozumieć, że są to najlepsze praktyki podczas projektowania interfejsu API RESTful. Specyfikacja HTTP jako taka nie ogranicza użycia PUT / POST z kilkoma ograniczeniami dotyczącymi tworzenia / aktualizowania zasobów. Spójrz na http://techoctave.com/c7/posts/71-twitter-rest-api-dissected, który podsumowuje najlepsze praktyki.

java_geek
źródło
Przeważnie, czytając cały ten hałas, wydajesz się być na kuli. Powiedziałbym jednak, że powinniśmy odwoływać się do PUT jako metody zastępowania, a nie do tworzenia / aktualizacji. Myślę, że lepiej opisuje w jednym, co robi.
thecoshman