REST'te PUT ve POST


5373

HTTP / 1.1 Spec'e göre:

POSTYöntem kökenli sunucu tarafından tanımlanan kaynağın yeni bir ikincil parçası olarak isteğe eklenmiş varlığa kabul etmesini talep etmek için kullanılır Request-URIiçindeRequest-Line

Başka bir deyişle, oluşturmakPOST için kullanılır .

PUTEkteki varlık tedarik altında saklanabilir yöntem istekleri Request-URI. Eğer Request-URImevcut bir kaynağa başvuruda, ekteki varlık sunucuda bulunanın birinin modifiye edilmiş versiyonu olarak düşünülmelidir. Bu, Request-URImevcut bir kaynağa işaret etmiyorsa ve bu URI, istekte bulunan kullanıcı aracısı tarafından yeni bir kaynak olarak tanımlanabiliyorsa, kaynak sunucu kaynağı bu URI ile oluşturabilir. "

Yani, oluşturmak veya değiştirmekPUT için kullanılır .

Peki, kaynak oluşturmak için hangisi kullanılmalıdır? Yoksa ikisini de desteklemeli mi?


56
HTTPbis'teki tanımları kullanmak faydalı olabilir - Roy, bunları açıklığa kavuşturmak için oldukça fazla çalışma yapmıştır. Bakınız: tools.ietf.org/html/…
Mark Nottingham

16
@ MarkNottingham'ın yorumunu en son revizyona getirmek için, HTTPbis'te tanımlandığı gibi POST ve PUT .
Marius Butuc

37
Bana öyle geliyor ki bu tartışma, HTTP Yöntemlerini CRUD işlemleri açısından tanımlayarak REST'i aşırı basitleştirmenin ortak uygulamasından kaynaklanıyor.
Stuporman

5
Ne yazık ki POST ile ilgili ilk cevaplar yanlış. Farklılıkların daha iyi bir açıklaması için cevabımı kontrol edin: stackoverflow.com/a/18243587/2458234
7hi4g0

23
PUT ve POST güvenli olmayan yöntemlerdir. Ancak, PUT idempotent, POST ise değil. - Daha fazla bilgi için: restcookbook.com/HTTP%20Methods/put-vs-post/…
Dinesh Saini

Yanıtlar:


4239

Genel:

Hem PUT hem de POST oluşturmak için kullanılabilir.

"Eylemi ne yapıyorsun?" Sorusunu sormalısın. ne kullanmanız gerektiğini ayırt etmek için. Soru sormak için bir API tasarladığınızı varsayalım. POST kullanmak istiyorsanız bunu bir soru listesine yaparsınız. PUT kullanmak istiyorsanız bunu belirli bir soruya yaparsınız.

Her ikisi de harika kullanılabilir, bu yüzden RESTful tasarımımda hangisini kullanmalıyım:

Hem PUT hem de POST'u desteklemenize gerek yoktur.

Kullanılan size kalmış. Ancak, istekte hangi nesneye başvurduğunuza bağlı olarak doğru olanı kullanmayı unutmayın.

Bazı düşünceler:

  • Oluşturduğunuz URL nesnelerini açıkça adlandırıyor veya sunucunun karar vermesine izin veriyor musunuz? Onları adlandırırsanız PUT kullanın. Sunucunun karar vermesine izin verirseniz, POST kullanın.
  • PUT idempotenttir, bu nedenle bir nesneyi iki kez PUT yaparsanız, hiçbir etkisi yoktur. Bu güzel bir özelliktir, bu yüzden mümkünse PUT kullanabilirsiniz.
  • PUT ile aynı nesne URL'sine sahip bir kaynağı güncelleyebilir veya oluşturabilirsiniz
  • POST ile bir URL'de değişiklik yaparak aynı anda gelen 2 isteğiniz olabilir ve bunlar nesnenin farklı bölümlerini güncelleyebilir.

Bir örnek:

Bu konuda SO üzerine başka bir cevabın bir parçası olarak aşağıdakileri yazdım :

İLETİ:

Bir kaynağı değiştirmek ve güncellemek için kullanılır

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

Aşağıdakilerin bir hata olduğunu unutmayın:

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

URL henüz oluşturulmamışsa, adı belirtirken URL'yi oluşturmak için POST kullanmamalısınız. Bu <new_question>henüz mevcut olmadığından 'kaynak bulunamadı' hatasıyla sonuçlanmalıdır . <new_question> İlk olarak kaynağı sunucuya koymalısınız .

Ancak POST kullanarak bir kaynak oluşturmak için böyle bir şey yapabilirsiniz:

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

Bu durumda kaynak adının belirtilmediğini, yeni nesnelerin URL yolunun size döndürüleceğini unutmayın.

KOYMAK:

Bir kaynak oluşturmak veya üzerine yazmak için kullanılır. Kaynakları belirtirken yeni URL.

Yeni bir kaynak için:

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

Mevcut bir kaynağın üzerine yazmak için:

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

Ek olarak ve biraz daha kısaca, RFC 7231 Bölüm 4.3.4 PUT belirtileri (vurgu eklenmiştir),

4.3.4. KOYMAK

PUT yöntemi, hedef kaynağın durumunun createdveya replacedistek iletisi bilgi yükünde yer alan temsil tarafından tanımlanan durumla olmasını ister .


1026
Bence PUT idempotent gerçeği yeterince vurgulayamaz düşünüyorum: ağ botched ve istemci isteği üzerinden olup olmadığını emin değilseniz, sadece ikinci (veya 100th) kez gönderebilir, ve garanti Bunun bir kez gönderme ile aynı etkiye sahip olduğu HTTP özellikleri.
Jörg W Mittag

77
@ Jörg W Mittag: Gerekli değil. İkinci kez, istek bu arada değiştirilirse (başka bir kullanıcı veya ilk isteğin kendisi tarafından değiştirilirse) 409 Çatışma veya başka bir şey döndürebilir.
Mitar

632
Yanılmıyorsam, vurgulamamız gereken şey PUT'un idempotent olarak tanımlanmasıdır . Sunucunuzu hala PUT'un doğru davranacağı şekilde yazmanız gerekiyor, değil mi? Belki de "PUT taşımacılığın, örneğin önbelleğe alma gibi taşımanın davranışını etkileyebilecek olan idempotence almasına neden olduğunu" söylemek daha iyidir.
Ian Ni-Lewis

150
@ JörgWMittag Idempotence catchphrase? "Gönder ve gönder ve arkadaşımı gönder, sonunda hiç fark etmez."
James Beninger

39
Bunları şöyle düşünüyor: PUT = ekle veya güncelle; POST = ekle. Yani iki PUT yaptığınızda - yeni bir kayıt alırsınız, iki POST yaptığınızda - iki yeni kayıt alırsınız.
Eugen Konkov

2218

Web'de şu ifadeleri bulabilirsiniz:

İkisi de doğru değil.


Daha iyi eylem idempotence dayalı PUT ve POST arasında seçim yapmaktır .

PUT , bir kaynak koymak anlamına gelir - verilen URL'de mevcut olanı tamamen farklı bir şeyle değiştirmek. Tanım olarak, bir PUT idempotenttir. İstediğiniz kadar yapın ve sonuç aynı. x=5idempotenttir. Bir kaynağı önceden mevcut olsun ya da olmasın PUT yapabilirsiniz (ör. Oluşturmak ya da Güncellemek için)!

POST bir kaynağı günceller, yardımcı kaynak ekler veya değişikliğe neden olur. POST, idempotent x++olmayan bir şekilde idempotent değildir.


Bu argümanla PUT, oluşturacağınız şeyin URL'sini bildiğinizde oluşturmak içindir. POST, oluşturmak istediğiniz şeylerin kategorisi için "fabrika" ya da yöneticinin URL'sini bildiğinizde oluşturmak için kullanılabilir.

yani:

POST /expense-report

veya:

PUT  /expense-report/10929

72
Kabul ediyorum, idempotence her nerede olursa olsun, başka türlü endişeleri ortadan kaldırmalı çünkü yanlış anlamak pek çok beklenmedik hataya neden olabilir.
Josh

16
POST bir kaynağı güncelleyebiliyorsa, bu nasıl idempotent değildir? Bir öğrencinin yaşını PUT kullanarak değiştirirsem ve bunu 10 kat daha fazla yaparsam, bir kez yapsam öğrencilerin yaşı aynı olur.
Jack Ukleja

28
@Schneider, bu durumda sunucunuz idempotence'i garanti etmek için ekstra çaba harcıyor, ancak reklamını yapmıyor. Tarayıcılar, böyle bir POST isteğini yeniden yüklemeye çalışırsa kullanıcıyı yine de uyarır.
Tobu

47
@Schneider POST yardımcı bir kaynak oluşturabilir; bu nedenle POST / gider raporları gibi koleksiyona POST yapabilirsiniz ve sunucunuzda, tamamen benzer olsalar bile, gönderdiğiniz isteklerin sayısı kadar çok varlık (gider raporları) oluşturur. Bunu, otomatik olarak artan birincil anahtarla DB tablosuna (/ gider raporları) aynı satırı eklemek olarak düşünün. Veriler aynı kalır, anahtar (bu durumda URI) sunucu tarafından oluşturulur ve diğer her ekleme (istek) için farklıdır. Yani, POST etkisi olabilir İdempotent olmak değil, aynı zamanda olabilir değil. Bu nedenle, POST idempotent değildir .
Snifff

11
Diyelim ki iki özelliğe sahip varlıklar var - nameve date. Var olan bir varlığımız varsa nameve datedaha sonra yalnızca a belirtmek için istekte bulunursa name, PUT'un uygun davranışı datevarlığın yok edilmesi olacaktır , oysa POST yalnızca belirtilen özellikleri güncelleyebilir ve belirtilmemiş özellikleri olduğu gibi bırakabilir istek yapılmadan önce. Kulağa doğru / makul geliyor mu, yoksa PUT'un yanlış kullanımı mı ( daha uygun gibi göründüğü, ancak henüz mevcut olmadığı görünen PATCH referanslarını gördüm )?
Jon z

707
  • POST bir URL'ye çocuk kaynağı oluşturur bir de sunucu tanımlı URL'ye.
  • Bir URL'ye PUT , kaynağı tümüyle tanımlı URL'de oluşturur / değiştirir .
  • URL'ye PATCH , istemcinin tanımladığı URL'deki kaynağın bir bölümünü günceller .

PUT ve POST için ilgili şartname RFC 2616 §9.5ff'dir.

POST bir alt kaynak oluşturur , bu nedenle POST /itemskaynağın altında yaşayan bir kaynak oluşturur /items. Örneğin. /items/1. Aynı gönderi paketini iki kez göndermek iki kaynak oluşturur.

PUT , istemci tarafından bilinen bir URL'de kaynak oluşturmak veya değiştirmek içindir .

Bu nedenle: PUT , yalnızca kaynak oluşturulmadan önce istemcinin URL'yi bildiği CREATE için bir adaydır. Örneğin. /blogs/nigel/entry/when_to_use_post_vs_putbaşlık kaynak anahtarı olarak kullanıldığından

PUT , zaten mevcutsa bilinen URL'deki kaynağı değiştirir, bu nedenle aynı isteği iki kez göndermenin bir etkisi olmaz. Başka bir deyişle, PUT'a yapılan çağrılar idempotenttir .

RFC şu şekildedir:

POST ve PUT istekleri arasındaki temel fark, İstek-URI'sinin farklı anlamına yansır. Bir POST isteğindeki URI, ekteki varlığı işleyecek kaynağı tanımlar. Bu kaynak veri kabul eden bir süreç, başka bir protokole açılan bir geçit veya ek açıklamaları kabul eden ayrı bir varlık olabilir. Buna karşılık, bir PUT isteğindeki URI, istekle birlikte gelen varlığı tanımlar - kullanıcı aracısı, URI'nin amaçlandığını bilir ve sunucunun, isteği başka bir kaynağa uygulamaması GEREKİR. Sunucu, isteğin farklı bir URI'ye uygulanmasını istiyorsa,

Not: PUT çoğunlukla kaynakları güncellemek için kullanılmıştır (bunları bütünlüklerinde değiştirerek), ancak son zamanlarda PUT kaynağın tüm kaynağın yerini aldığını belirttiği için mevcut kaynakları güncellemek için PATCH kullanımına yönelik bir hareket vardır. RFC 5789.

Güncelleme 2018 : PUT'u önlemek için yapılabilecek bir durum var. Bkz. "PUT'suz REST"

“PUT'suz REST” tekniği ile fikir, tüketicilerin yeni 'isimsiz' talep kaynakları yayınlamaya zorlanmasıdır. Daha önce tartışıldığı gibi, bir müşterinin posta adresini değiştirmek, farklı bir posta adresi alanı değeri olan bir "Müşteri" kaynağının PUT'u değil, yeni bir "ChangeOfAddress" kaynağının POST'udur.

alınan THOUGHTWORKS ait Prakash Subramaniam tarafından Kaynak Modelleme - REST API Tasarım

Bu, API'yı birden çok istemcinin tek bir kaynağı güncellemesiyle durum geçişi sorunlarından kaçınmaya zorlar ve olay kaynağı ve CQRS ile daha iyi eşleşir. İş eşzamansız olarak yapıldığında, dönüşümü POSTA ETMEK ve uygulanmasını beklemek uygun görünüyor.


53
Veya çitin diğer tarafından: İstemci, sonuçta elde edilen kaynağın adresini belirlerse PUT, eğer sunucu yaparsa POST.
DanMan

3
Sanırım @DanMan'ın neyi işaret ettiğini daha basit bir şekilde ortaya koymak için bu cevabın düzenlenmesi gerekiyor. Burada en değerli bulduğum şey, sonunda bir PUT'un yalnızca tüm kaynağı değiştirmek için kullanılması gerektiğini belirten not.
Hermes

3
PATCH en az birkaç yıl boyunca gerçekçi bir seçenek değil, ama ideolojiye katılıyorum.
ezmek

4
Anlamaya çalışıyorum, ancak bir şey oluşturmak için PUT kullanmak sadece istemci kaynak henüz mevcut olmadığından emin olursa, mantıklı olurdu, değil mi? Blog örneğini izleyerek, birkaç yıl içinde yüzlerce blog yazısı oluşturduğunuzu, ardından yanlışlıkla iki yıl önce bir gönderiyle aynı başlığı seçtiğinizi varsayalım. Şimdi gittin ve amaçlanmayan bu görevi değiştirdin PUT oluşturmak için PUT kullanmak istemcinin neyin alındığını ve neyin olmadığını izlemesini gerektirir ve tamamen farklı iki şey yapan güzergahlara sahip olmanın yanı sıra kazalara ve istenmeyen yan etkilere neden olabilir mi?
galaxyAbstractor

5
Haklısın. Bir blog postasını mevcut bir URL ile aynı URL'ye koymak, mevcut postanın güncellenmesine neden olur (ancak ilk olarak bir GET ile kontrol edebilirsiniz). Bu, yalnızca başlığı URL olarak kullanmanın neden kötü bir fikir olacağını gösterir. Ancak verilerde doğal bir anahtar olduğu her yerde işe yarayacaktır ... benim deneyimime göre nadirdir. Veya GUID'ler kullandıysanız
Nigel Thorne

221

Özet:

Oluşturmak:

Hem PUT hem de POST ile aşağıdaki şekilde gerçekleştirilebilir:

KOYMAK

Oluşturur ile yeni bir kaynak newResourceId / kaynaklar URI veya altında, tanımlayıcı olarak toplanması .

PUT /resources/<newResourceId> HTTP/1.1 

İLETİ

Oluşturur A / kaynaklar URI veya altında yeni bir kaynak koleksiyonu . Genellikle tanımlayıcı sunucu tarafından döndürülür.

POST /resources HTTP/1.1

Güncelleme:

Can sadece şu şekilde PUT ile yapılabilir:

KOYMAK

İle kaynak günceller existingResourceId / kaynaklar URI veya altında, tanımlayıcı olarak koleksiyon .

PUT /resources/<existingResourceId> HTTP/1.1

Açıklama:

Genel olarak REST ve URI ile uğraşırken, sahip jenerik üzerinde solda ve spesifik üzerinde sağa . Jenerik genellikle denir koleksiyonları ve daha spesifik ürün çağrılabilir kaynak . Bir kaynağın bir koleksiyon içerebileceğini unutmayın .

Örnekler:

<- genel - özel ->

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

Eğer edilir POST kullandığınızda hep bir atıfta koleksiyon diyorsunuz yüzden her zaman:

POST /users HTTP/1.1

kullanıcılar koleksiyonuna yeni bir kullanıcı gönderiyorsunuz .

Devam edip böyle bir şey denerseniz:

POST /users/john HTTP/1.1

işe yarayacaktır, ancak anlamsal olarak , kullanıcılar koleksiyonunun altındaki john koleksiyonuna bir kaynak eklemek istediğinizi söylüyorsunuz .

PUT'u kullandıktan sonra , muhtemelen bir koleksiyon içindeki bir kaynağa veya tek bir öğeye başvuruyorsunuz . Yani dediğin zaman:

PUT /users/john HTTP/1.1

sunucu güncellemesini söylüyorsunuz veya yoksa kullanıcı koleksiyonu altındaki john kaynağı oluşturuyorsunuz .

spec:

Spesifikasyonun bazı önemli kısımlarını vurgulayayım:

İLETİ

POST yöntemi kökenli sunucu bu isteğe için kullanılır kabul bir şekilde isteğe eklenmiş varlığa yeni bir ikincil parçası İsteği-Line Request-URI tarafından tanımlanan kaynağın

Bu nedenle, koleksiyon üzerinde yeni bir kaynak oluşturur .

KOYMAK

PUT kapalı varlık olması yöntem istekleri saklanan sağlanan Request-URI altında. İstek URI'sı zaten var olan bir kaynağa başvuruyorsa , ekteki varlık , kaynak sunucuda bulunanın değiştirilmiş bir sürümü olarak düşünülmelidir . İstenen URI yoksa varolan göstermiyor kaynak ve URI'nın olduğunu yetenekli bir olarak tanımlanan olma yeni kaynak talep eden kullanıcı aracısı tarafından, menşe sunucu olabilir oluşturmak olduğunu URI ile kaynak."

Bu nedenle, kaynağın varlığına göre oluşturun veya güncelleyin .

Referans:


11
Bu yazı POST'un belirli bir koleksiyona (URI) bir çocuk olarak "bir şey" eklediğini anlamamda bana yardımcı olurken PUT, verilen URI konumunda "bir şeyi" açıkça tanımlar.
kwah

3
Bence en iyi cevap bu, bence: bu "POST bir kaynağı güncelleyemez" saçmalık. "Güncelleme yalnızca PUT ile yapılabilir" ifadesini beğendim.
Thomas

4
Hayır, PUT güncelleme veya oluşturma için değildir. Değiştirmek içindir. Oluşturma etkisi için hiçbir şeyi bir şeyle değiştiremeyeceğinizi unutmayın.
thecoshman

2
@ 7hi4g0 PUT tam bir değiştirme ile güncelleme içindir, başka bir deyişle, onun yerine geçer. Hiçbir şeyi bir şeyle ya da tamamen yeni bir şeyle değiştirirsiniz. PUT, küçük bir değişiklik yapmak için değildir (istemcinizin bu küçük değişikliği yapması ve tüm yeni sürümü, aynı kalanı bile sağlaması yoksa). Kısmi değişiklik için PATCH tercih edilen yöntemdir.
thecoshman

1
@thecoshman Yapabilirsin, ama yaratmanın da orada olduğu çok açık olmazdı. Bu durumda, açık olmak daha iyidir.
7hi4g0

175

POST "Burada bir kullanıcı oluşturmak, benim için oluşturmak" için giriş ".

PUT "Kullanıcı 5 için veriler" ifadesinde olduğu gibi "zaten varsa ekle, değiştir" anlamına gelir.

Sen POSTexample.com/users için Bilmiyorsanız beriURL Henüz kullanıcı, sunucu bunu oluşturmak istiyorum.

Sen PUTdeğiştirmek istediğiniz beri / a oluşturmak example.com/users/id için özgü kullanıcı.

Aynı verilerle iki kez POST yapmak farklı kimliğe sahip iki özdeş kullanıcı oluşturmak anlamına gelir. Aynı verilerle iki kez PUT yapmak kullanıcıyı ilk oluşturur ve ikinci kez aynı duruma günceller (değişiklik yok). PUTKaç kez gerçekleştirirseniz yapın aynı durumla sonuçlandığınız için, her seferinde "eşit derecede güçlü" olduğu söylenir - aynı zamanda. Bu, istekleri otomatik olarak yeniden denemek için kullanışlıdır. Tarayıcıda geri düğmesine bastığınızda artık 'yeniden göndermek istediğinizden emin değilsiniz'.

Genel bir tavsiye, POSTsunucunun URLkaynaklarınızın üretimini kontrol altında tutması gerektiğinde kullanmaktır . PUTAksi takdirde kullanın . Tercih PUT üzerinde POST.


12
Özensizlik, yaygın olarak ihtiyacınız olan sadece iki fiil olduğu öğretilmesine neden olabilir: GET ve POST. GET almak için, değiştirmek için POST. PUT ve DELETE bile POST kullanılarak gerçekleştirildi. PUT'un gerçekten ne anlama geldiğini sormak 25 yıl sonra belki de ilk başta yanlış öğrendiğimize dair bir işaret. REST popülaritesi insanları geçmiş kötü hataları öğrenmemiz gereken temel noktalara geri götürdü. POST aşırı kullanıldı ve şimdi yaygın olarak yanlış öğretildi. En iyi bölüm: "Aynı verilerle iki kez POST yapmak iki özdeş [kaynak] oluşturmak anlamına gelir". Harika bir nokta!
maxpolk

1
user 5Henüz mevcut değilse örneğinizde olduğu gibi kimlikle bir kayıt oluşturmak için PUT'u nasıl kullanabilirsiniz ? Bunu mu demek istediniz update, replace if already exists? falan
Luke

@Coulton: Ne yazdığımı kastediyordum. / Users / 5 ve # 5 öğesine PUT eklemediyseniz, kullanıcı 5'i eklersiniz.
Alexander Torstling

@Coulton: Ayrıca mevcut bir kaynağın değerini bütünüyle değiştirmek için PUTde kullanılabilir .
DavidRR

1
"POST yerine PUT tercih" ... bunu haklı çıkarmak ister misiniz?
thecoshman

173

"Pragmatik" tavsiyemi eklemek istiyorum. Kaydettiğiniz nesnenin alınabileceği "kimliği" bildiğinizde PUT kullanın. Gelecekte aramalar veya güncellemeler yapmanız için döndürülecek bir veritabanı oluşturulmuş kimliğe ihtiyacınız varsa, PUT kullanımı çok iyi çalışmaz.

So: Mevcut bir kullanıcıyı veya istemcinin kimliği oluşturduğu ve kimliğin benzersiz olduğu doğrulanan bir kullanıcıyı kaydetmek için:

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

Aksi takdirde, nesneyi başlangıçta oluşturmak için POST'u ve nesneyi güncellemek için PUT'u kullanın:

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

17
Aslında öyle olmalı POST /users. ( /usersÇoğul olduğunu unutmayın .) Bu, yeni bir kullanıcı oluşturma ve onu /userskoleksiyonun alt kaynağı yapma etkisine sahiptir .
DavidRR

6
@DavidRR dürüst olmak gerekirse, grupların nasıl ele alınacağı tamamen başka bir tartışmadır. GET /usersmantıklı, istediğiniz gibi okur, ancak ('yeni kullanıcı için 5 olsun' garip, ama 'beni 5 kullanıcı olsun' doğru okur çünkü GET /user/<id>veya ile POST /user( ok dedi yeni kullanıcı için yük ile) iyi olurdu . Muhtemelen yine de çoğulculuğun yanına düşecektim :)
thecoshman

126

Oluşturmak için POST, güncellemek için PUT kullanın. Zaten Ruby on Rails böyle yapıyor.

PUT    /items/1      #=> update
POST   /items        #=> create

4
POST /itemsönceden tanımlanmış bir kaynağa ('öğe') yeni bir öğe ekler. Yanıtın dediği gibi "grup oluştur" değil. Bunun neden 12 oyu olduğunu anlamıyorum.
David J.

Kutudan çıkar çıkmaz Rails, REST yoluyla 'grup oluşturmayı' desteklemez. 'Bir kaynak oluşturmak' demek istediğim 'grup oluşturmak' için bunu kaynak koduyla yapmanız gerekir.
David J.

8
Bu adil bir kılavuzdur, ancak aşırı basitleştirmedir. Diğer cevaplarda belirtildiği gibi, her iki yöntem de hem oluşturma hem de güncelleme için kullanılabilir.
Brad Koch

2
Cevaba küçük bir değişiklikle katılıyorum. Oluşturmak için POST ve kaynağı tamamen güncellemek için PUT kullanın. Kısmi güncellemeler için PUT veya PATCH kullanabiliriz. Bir grubun durumunu güncellemek istediğimizi varsayalım. Durum ile PUT / gruplar / 1 / durumunu kullanabiliriz, yük
taşımadaki

2
Ayrıca, bir kaynak oluşturmakPUT /items/42 için de geçerli olduğu , ancak istemcinin kaynağı adlandırma ayrıcalığına sahip olduğu açıkça belirtilmelidir . (Rails, bir istemciye bu adlandırma ayrıcalığına izin veriyor mu?)
DavidRR

123

Her ikisi de istemciden sunucuya veri aktarımı için kullanılır, ancak aralarında küçük farklılıklar vardır, bunlar:

Resim açıklamasını buraya girin

Analoji:

  • PUT yani al ve koy nerede olduğunu .
  • Göndermek posta olarak POST sonrası ofis.

resim açıklamasını buraya girin

Sosyal Medya / Ağ Analojisi:

  • İleti sosyal medyada: Biz mesajı ne zaman, yeni yayın oluşturulur.
  • Önceden yayınladığımız mesaj için koy (yani düzenle).

21
@MobileMon Hayır, REST yöntemleri CRUD değildir.
jlr

1
UPSERTS için PUT diyebilirim
Hola Soy Edu Feliz Navidad

@MobileMon no: Yeni bir kaynak oluşturduğunuzda ve bunu elde etmek için son bitiş noktasını bilmediğinizde POST. Diğer durumlar için PUT.
Portekoi

67

REST çok üst düzey bir kavramdır. Aslında, HTTP'den bile bahsetmiyor!

HTTP'de REST'in nasıl uygulanacağı konusunda şüpheleriniz varsa, Atom Yayın Protokolü'ne (AtomPub) her zaman göz atabilirsiniz. spesifikasyonuna . AtomPub, birçok HTTP ve REST armatürü tarafından geliştirilen, REST'in mucidi ve HTTP'nin (ortak) mucidi Roy Fielding'den bazı girdilerle HTTP ile RESTful web servislerini yazmak için bir standarttır.

Aslında, AtomPub'ı doğrudan da kullanabilirsiniz. Blog topluluğundan çıkarken, hiçbir şekilde blog oluşturmayla sınırlı değildir: HTTP aracılığıyla rastgele (yuvalanmış) keyfi kaynak koleksiyonlarıyla RESTfully etkileşime girmek için genel bir protokoldür. Uygulamanızı iç içe geçmiş bir kaynak koleksiyonu olarak temsil edebiliyorsanız, AtomPub'u kullanabilir ve PUT veya POST kullanıp kullanmayacağınız, hangi HTTP Durum Kodlarının döndürüleceği ve tüm bu ayrıntılar hakkında endişelenmeyebilirsiniz.

AtomPub'un kaynak oluşturma hakkında söylediği şey budur (bölüm 9.2):

Bir Koleksiyona üye eklemek için istemciler Koleksiyonun URI'sına POST istekleri gönderir.


8
PUT'un kaynak oluşturmasına izin vermede yanlış bir şey yok. Bunun, istemcinin URL'yi sağladığı anlamına geldiğini unutmayın.
Julian Reschke

5
PUT'un kaynak oluşturmasına izin vermede çok yanlış bir şey var: istemci URL'yi sağlıyor. Sunucunun işi bu!
Joshcodes

@Joshcodes İstemci kimlikleri oluşturmak her zaman sunucunun işi değildir. Müşterilerin kaynak kimliği olarak bir tür UUID oluşturmasına izin veren tasarımları giderek gördüm. Bu tasarım özellikle ölçeği arttırmak için kendini ödünç vermektedir.
Justin Ohms

@JustinOhms Müşteri tarafından oluşturulan kimlikler hakkındaki görüşünüze katılıyorum (yan not: 2008'den beri benim tarafımdan tasarlanan tüm sistemler istemcinin kimliği UUID / Guid olarak oluşturmasını gerektirir). Bu, istemcinin URL'yi belirtmesi gerektiği anlamına gelmez.
Joshcodes

1
Evet, kaynak zaten varsa, PUT kullanın. Ancak, hemen hemen tüm durumlarda kaynaklar POST ile oluşturulmalı ve istemci URL'yi sağlamamalıdır. Roy Fielding bu ifadeyi kabul ediyor FWIW: roy.gbiv.com/untangled/2008/rest-apis-must-be-hypertext-driven
Joshcodes

61

HTTP + REST API'sine sahip bir sunucuda kaynak oluşturmak için PUT veya POST kullanıp kullanmama kararı, URL yapısının kime ait olduğuna bağlıdır. Müşterinin URL yapısını bilmesi veya tanımlamaya katılması, SOA'dan kaynaklanan istenmeyen bağlantılara benzer gereksiz bir bağlantıdır. REST'in bu kadar popüler olmasının nedeni kaçan kaplin tipleridir. Bu nedenle, kullanılacak doğru yöntem POST'tur.Bu kuralın istisnaları vardır ve istemci, dağıttığı kaynakların konum yapısı üzerinde kontrolü elinde tutmak istediğinde ortaya çıkar. Bu nadirdir ve muhtemelen başka bir şeyin yanlış olduğu anlamına gelir.

Bu noktada bazı insanlar RESTful-URL'leri kullanılırsa, istemcinin kaynağın URL'sini bildiğini ve bu nedenle bir PUT'un kabul edilebilir olduğunu iddia edecektir . Sonuçta, bu yüzden kanonik, normalleştirilmiş, Ruby on Rails, Django URL'leri önemlidir, Twitter API'sına bakın… blah blah blah. Bu insanların Restful-URL diye bir şey olmadığını ve Roy Fielding'in kendisinin şunları söylediğini anlaması gerekiyor :

REST API'sı sabit kaynak adları veya hiyerarşileri tanımlamamalıdır (istemci ve sunucunun bariz bir şekilde birleştirilmesi). Sunucular kendi ad alanlarını denetleme özgürlüğüne sahip olmalıdır. Bunun yerine, sunuculara, ortam türleri ve bağlantı ilişkileri içindeki bu yönergeleri tanımlayarak, istemcilere HTML formlarında ve URI şablonlarında yapılan gibi uygun URI'lerin nasıl oluşturulacağı konusunda talimat verme izni verin. [Buradaki başarısızlık, istemcilerin, RPC'nin işlevsel kuplajına veri odaklı eşdeğeri olan etki alanına özgü bir standart gibi bant dışı bilgiler nedeniyle bir kaynak yapısı üstlendiğini ima eder].

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

RESTful-URL fikri , sunucu URL yapısından sorumlu olduğu için REST'in ihlalidir ve eşleşmeyi önlemek için nasıl kullanılacağına karar vermede serbest olmalıdır. Bu kafanız karışırsa, API tasarımında kendini keşfetmenin önemini okursunuz.

Kaynak oluşturmak için POST kullanımı, tasarım dikkate alınmaktadır, çünkü POST idempotent değildir. Bu, bir POST'u birkaç kez tekrarlamanın her seferinde aynı davranışı garanti etmediği anlamına gelir. Bu, insanları gerekmediğinde kaynak oluşturmak için PUT'u kullanmaya korkutur. Bunun yanlış olduğunu biliyorlar (POST CREATE için) ama yine de yapıyorlar çünkü bu sorunu nasıl çözeceklerini bilmiyorlar. Bu endişe aşağıdaki durumda ortaya çıkar:

  1. Istemci sunucuya yeni bir kaynak POST.
  2. Sunucu isteği işler ve bir yanıt gönderir.
  3. İstemci hiçbir zaman yanıtı almaz.
  4. Sunucu, istemcinin yanıtı almadığını bilmiyor.
  5. İstemcinin kaynak için bir URL'si yoktur (bu nedenle PUT bir seçenek değildir) ve POST'u tekrarlar.
  6. POST idempotent değil ve sunucu…

6. Adım, insanların ne yapmaları gerektiği konusunda kafalarını karıştırdığı yerdir. Ancak, bu sorunu çözmek için bir çamur oluşturmak için hiçbir neden yoktur. Bunun yerine, HTTP RFC 2616'da belirtildiği gibi kullanılabilir ve sunucu şunları yanıtlar:

10.4.10 409 Çatışma

Kaynağın geçerli durumu ile bir çakışma nedeniyle istek tamamlanamadı. Bu koda yalnızca kullanıcının çakışmayı çözebileceği ve isteği yeniden gönderebileceği durumlarda izin verilir. Yanıt kuruluşu yeterli miktarda içermelidir

kullanıcının çatışmanın kaynağını tanıması için bilgi. İdeal olarak, yanıt veren varlık, sorunu çözmek için kullanıcı veya kullanıcı aracısı için yeterli bilgi içerecektir; ancak bu mümkün olmayabilir ve gerekli değildir.

Çatışmaların bir PUT isteğine yanıt olarak ortaya çıkması muhtemeldir. Örneğin, sürüm oluşturma kullanılıyorsa ve PUT olan varlık, önceki (üçüncü taraf) bir istek tarafından yapılanlarla çakışan bir kaynakta değişiklikler içeriyorsa, sunucu, isteği tamamlayamayacağını belirtmek için 409 yanıtını kullanabilir . Bu durumda, yanıt veren varlık, iki tür arasındaki yanıtın Content-Type tarafından tanımlanan bir biçimde farklılıklarının bir listesini içerecektir.

409 Çatışma durum kodu ile yanıt vermek doğru başvurudur çünkü :

  • Zaten sistemde bulunan bir kaynakla eşleşen bir kimliğe sahip bir veri POST'u gerçekleştirmek “kaynağın mevcut durumu ile bir çelişkidir”.
  • Önemli kısmı istemcinin sunucunun kaynağına sahip olduğunu anlaması ve uygun önlemleri almasıdır. Bu, “kullanıcının çakışmayı çözebileceği ve isteği yeniden gönderebileceği beklenen bir durumdur.”
  • Çakışan kimliğe sahip kaynağın URL'sini ve kaynak için uygun önkoşulları içeren bir yanıt, RFC 2616 için ideal durum olan "kullanıcı veya kullanıcı aracısının sorunu düzeltmesi için yeterli bilgi" sağlayacaktır.

2616 numaralı RFC 7231 sürümüne dayalı güncelleştirme

RFC 7231 , 2616'nın yerini alacak şekilde tasarlanmıştır ve Bölüm 4.3.3'te bir POST için olası aşağıdaki yanıtı açıklar

Bir POST işlemenin sonucu mevcut bir kaynağın temsiline eşdeğerse, bir kaynak sunucu, Konum alanındaki mevcut kaynağın tanımlayıcısına 303 (Diğerine bakın) yanıtı göndererek kullanıcı ajanını bu kaynağa yönlendirebilir. Bunun, kullanıcı aracısına bir kaynak tanımlayıcı sağlama ve temsili, paylaşılan önbelleğe almaya daha uygun bir yöntemle aktarma avantajlarına sahiptir; bununla birlikte, kullanıcı aracısı zaten önbelleğe alınmış temsile sahip değilse, ekstra bir istek pahasına.

Şimdi bir POST tekrarlandığında 303'ü döndürmek cazip gelebilir. Ancak bunun tam tersi doğrudur. 303 döndürmek yalnızca birden çok oluşturma isteği (farklı kaynaklar oluşturma) aynı içeriği döndürürse mantıklı olur. Buna örnek olarak, müşterinin her seferinde yeniden indirmesi gerekmeyen "istek mesajınızı gönderdiğiniz için teşekkür ederiz" verilebilir. RFC 7231 hala bölüm 4.2.2'de POST'un idempotent olmayacağını ve POST'un yaratılmak için kullanılmasını sürdürmesini sürdürmektedir.

Bununla ilgili daha fazla bilgi için bu makaleyi okuyun .


409 Çakışma yanıtı, zaten var olan bir kullanıcı adıyla yeni bir hesap oluşturmaya çalışmak gibi uygun bir kod olabilir mi? Özellikle çakışmaları sürümleme için 409 kullanıyorum, ancak cevabınızı okuduktan sonra herhangi bir "yinelenen" istek için kullanılmaması gerekip gerekmediğini merak ediyorum.
Eric

@EricB. Evet, "kaynağın mevcut durumu ile bir çakışma nedeniyle" tanımladığınız durumda işlem başarısız olur. Ayrıca, kullanıcının çakışmayı çözmesini beklemek mantıklıdır ve ileti gövdesinin kullanıcıyı yalnızca kullanıcı adının zaten var olduğunu bildirmesi gerekir.
Joshcodes

@Joshcodes anlaşmazlık çözümü süreci hakkında daha fazla şey söyleyebilir misiniz? Bu durumda, kullanıcı adı zaten mevcutsa, istemcinin son kullanıcıdan farklı bir kullanıcı adı istemesi beklenir mi? İstemci aslında kullanıcı adını değiştirmek için POST kullanmaya çalışıyorsa ne olur? Parametreleri güncellemek için PUT istekleri kullanılmalı mıdır, POST ise birer birer veya birkaç tane olmak üzere nesne oluşturmak için kullanılır mı? Teşekkürler.
BFar

@ BFar2, kullanıcı adı zaten varsa, istemciden kullanıcıyı uyarması gerekir. Kullanıcı adını değiştirmek için, kullanıcı adının önceden oluşturulmuş bir kaynağın değiştirilmesi gereken bir parçası olduğu varsayılarak, doğru olduğunuz için PUT kullanılır, POST, oluşturma için her zaman ve güncellemeler için PUT kullanılır.
Joshcodes

kısa ve etkili bir dil kullanarak şeyleri açıklamak da istenen bir beceridir
Junchen Liu

53

RFC 2616'nın PUT tanımından bu tavsiyeyi beğendim :

POST ve PUT istekleri arasındaki temel fark, İstek-URI'sinin farklı anlamına yansır. Bir POST isteğindeki URI, ekteki varlığı işleyecek kaynağı tanımlar. Bu kaynak veri kabul eden bir süreç, başka bir protokole açılan bir geçit veya ek açıklamaları kabul eden ayrı bir varlık olabilir. Buna karşılık, bir PUT isteğindeki URI, istekle birlikte gelen varlığı tanımlar - kullanıcı aracısı, URI'nin amaçlandığını bilir ve sunucunun, isteği başka bir kaynağa uygulamaması GEREKİR.

Buradaki diğer tavsiyeyle bu, PUT'un zaten bir adı olan kaynaklara en iyi şekilde uygulandığı ve POST'un mevcut bir kaynak altında yeni bir nesne oluşturmak (ve sunucunun adını vermesine izin vermek) için iyi olduğunu gösterir.

Bunu ve PUT üzerindeki idempotency gereksinimlerini şu şekilde yorumluyorum:

  • POST, bir koleksiyon altında yeni nesneler oluşturmak için iyidir (ve oluşturma işleminin idempotent olması gerekmez)
  • PUT, mevcut nesneleri güncellemek için iyidir (ve güncellemenin idempotent olması gerekir)
  • POST, mevcut nesnelere idempotent olmayan güncellemeler için de kullanılabilir (özellikle, her şeyi belirtmeden bir nesnenin bir kısmını değiştirmek - düşünürseniz, bir koleksiyonun yeni bir üyesini oluşturmak aslında bu türden özel bir durumdur koleksiyonun bakış açısından)
  • PUT, yalnızca istemcinin kaynağı adlandırmasına izin veriyorsanız oluşturma için de kullanılabilir. Ancak REST istemcilerinin URL yapısı hakkında varsayımlarda bulunmaları gerekmediğinden, bu, amaçlanan ruh açısından daha azdır.

3
"POST, mevcut nesnelere idempotent olmayan güncellemeler için de kullanılabilir (özellikle, her şeyi belirtmeden bir nesnenin bir kısmını değiştirmek" PATCH bunun içindir
Snuggs

48

Kısacası:

PUT idempotent'tir, burada aynı işlem bir kez veya birden çok kez yürütülürse kaynak durumu aynı olur.

POST , işlemin tek bir zamanın çalıştırılmasına kıyasla birden çok kez yürütülmesi durumunda kaynak durumunun farklı olabileceği idempotent değildir.

Veritabanı sorgusu ile benzerlik

PUT "GÜNCELLEME ÖĞRENCİ SETİ adresi =" abc "ye benzer şekilde düşünebilirsiniz. Burada id =" 123 ";

POST "ÖĞRENCİYE GİRİN (ad, adres) DEĞERLERİ (" abc "," xyzzz ");

Öğrenci Kimliği otomatik olarak oluşturulur.

PUT ile, aynı sorgu birden çok kez veya bir kez yürütülürse, ÖĞRENCİ tablo durumu aynı kalır.

POST durumunda, aynı sorgu birden çok kez yürütülürse, veritabanında birden fazla Öğrenci kaydı oluşturulur ve "INSERT" sorgusunun her yürütülmesinde veritabanı durumu değişir.

NOT: PUT, üzerinde güncelleme yapılması gereken bir kaynak konumuna (zaten kaynak) ihtiyaç duyarken, POST bunu gerektirmez. Bu nedenle, sezgisel olarak POST yeni bir kaynak oluşturmak içindir, ancak mevcut kaynağın güncellenmesi için PUT gereklidir.

Bazıları bu güncellemelerin POST ile yapılabileceğini düşünebilir. Hangisinin güncellemeler için kullanılacağı veya hangisinin oluşturma için kullanılacağı zor bir kural yoktur. Yine bunlar sözleşmelerdir ve sezgisel olarak yukarıda belirtilen akıl yürütme eğilimindeyim ve onu takip ediyorum.


6
için PUT INSERT veya UPDATE sorgusuna benzer
Eugen Konkov

1
Aslında PUT "UPDATE ÖĞRENCİ SETİ adresi =" abc "ye benzeyebilirsiniz, burada id =" 123 "; PATCH için bir ifade olur." UPDATE ÖĞRENCİ SET adresi = "abc", ad = "newname" nerede id = " 123 "PUT için doğru bir benzetme olur
mko

Put ayrıca INSERT için de kullanılabilir. Örneğin, sunucunuz aynı dosyayı birden çok kez yüklemeye çalıştığınızı belirlediğinde, isteğinizi idempotent yapar. (Yeni dosya yüklemesi yapılmaz).
kiwicomb123

43

POST, bir posta kutusuna mektup göndermek veya bir e-posta kuyruğuna e-posta göndermek gibidir. PUT, bir nesneyi bir cubby deliğine veya raftaki bir yere koyduğunuzda olduğu gibidir (bilinen bir adresi vardır).

POST ile, QUEUE veya COLLECTION adresine gönderiyorsunuz. PUT ile ITEM'in adresini girersiniz.

PUT idempotenttir. İsteği 100 kez gönderebilirsiniz ve önemli olmayacaktır. POST idempotent değil. İsteği 100 kez gönderirseniz, posta kutunuza 100 e-posta veya 100 harf alırsınız.

Genel bir kural: öğenin kimliğini veya adını biliyorsanız, PUT kullanın. Öğenin kimliğinin veya adının alıcı tarafça atanmasını istiyorsanız POST'u kullanın.

POST ve PUT karşılaştırması


1
Hayır, PUT, URL'yi bildiğiniz anlamına gelir. Yalnızca kimliği biliyorsanız, URL'yi almak için bu kimlikle birlikte POST yapın.
Joshcodes

6
Kimlik URL'nin bir parçasıdır, bu nedenle evet, URL'yi biliyorsanız (kimliği içeren) PUT kullanın.
Homer6

Hayır, URL sunucu tarafından belirlenir ve kimlik mutlaka URL'nin bir parçası değildir. Roy Fielding size aynısını söylerdi ya da tezini okuyabilirsiniz .
Joshcodes

@Joshcodes, bu REST olduğunu varsayar mı? RESTful mimarisinde, öğe kimliği kesinlikle: / people / 123 adresinde olduğu gibi URL'nin bir parçasıdır. Bu siteyi REST için beğendim: microformats.org/wiki/rest/urls
Beez

1
@ Mircoformats bağlantısından yararlanın, sunucuların URL'lerini yapılandırmaları için iyi bir yol önerir, ancak sunucu URL'yi belirler. İstemci asla yanına gelmez. Bkz Cevabımı veya ilgili makale bunu anlamak yoksa.
Joshcodes

39

Yeni cevap (şimdi REST'i daha iyi anladığım için):

PUT yalnızca, hizmetin bundan sonra, istemci tarafından tanımlanan kaynağın temsillerini oluşturmak için hangi içeriğin kullanılması gerektiğinin bir ifadesidir; POST, hizmetin bundan böyle hangi içeriği içermesi gerektiğine dair bir ifadedir (muhtemelen çoğaltılacaktır) ancak bu içeriğin nasıl tanımlanacağı sunucuya bağlıdır.

PUT x( xbir kaynağı tanımlarsa ): "Tarafından tanımlanan kaynağın içeriğini içeriğimle değiştir x."

PUT x( xbir kaynağı tanımlamazsa): "İçeriğimi içeren yeni bir kaynak oluştur ve xtanımlamak için kullan."

POST x: "İçeriğimi sakla ve bana adı geçen içeriği (muhtemelen başka içerikle karıştırılmış) içeren bir kaynağı (eski veya yeni) tanımlamak için kullanabileceğim bir tanımlayıcı ver. Adı geçen kaynak, xtanımlayanla aynı veya ona bağlı olmalıdır ." " Y 'in kaynak bağlı olduğunu X tipik olarak, ama zorunlu olarak yaparak uygulanmadı s kaynak'" y bir alt yolunu x (örneğin X = /foove Y = /foo/bar) ile temsil (ler) değiştirerek X varlığını yansıtacak 'in kaynak yeni bir kaynağın, örneğin ykaynağı ve bazı meta veriler. URL'ler REST'te opak olduğundan, yalnızca ikincisi iyi tasarım için gerçekten önemlidir - yapmanız gerekir hiper medya hizmeti yönlendirmek için istemci tarafı URL yapısı yerine.

REST'te, "içerik" içeren bir kaynak diye bir şey yoktur. Hizmetin gösterimleri tutarlı bir şekilde oluşturmak için kullandığı verilere "içerik" denir. Genellikle bir veritabanındaki veya dosyadaki bazı ilgili satırlardan oluşur (örneğin bir görüntü dosyası). Kullanıcının içeriğini hizmetin kullanabileceği bir şeye dönüştürmek, örneğin bir JSON yükünü SQL ifadelerine dönüştürmek hizmete kalmıştır.

Orijinal cevap (okunması daha kolay olabilir) :

PUT /something( /somethingzaten varsa): "Ne varsa al /somethingve yerine verdiğim şeyle değiştir."

PUT /something(eğer /somethingzaten mevcut değilse): "Sana verdiğim şeyi al ve koy /something."

POST /something: "Size verdiğim şeyi alın ve /somethingişiniz bittiğinde bana URL'sini verdiğiniz sürece istediğiniz yere koyun ."


Ancak kimlik oluşturma yönteminiz Otomatik Artımdayken PUT'u yeni bir kaynak yoksa oluşturmak için nasıl kullanabilirsiniz? Genellikle ORM'ler, örneğin POST'ta olmasını istediğiniz gibi sizin için otomatik olarak kimlik oluşturur. Bu, PUT'u doğru bir şekilde uygulamak istiyorsanız, kimlik otomatik üretiminizi değiştirmeniz gerektiği anlamına mı geliyor? Cevap evet ise bu çok garip.
Roni Axelrad

1
@RoniAxelrad: PUT, ifadeye anahtarı eklediğiniz bir veritabanı "INSERT OR UPDATE" ifadesine benzer, bu nedenle yalnızca çarpışma olmayacağı durumlarda geçerlidir. Örneğin. alan adınızda bir 'doğal anahtar' var veya bir rehber kullanıyorsunuz. POST, otomatik artan anahtarlı bir tabloya ekleme gibidir. Veritabanına, eklendikten sonra hangi kimliği aldığını söylemelisiniz. "EKLE VEYA GÜNCELLE" seçeneğinin, varsa önceki verilerin yerini alacağını unutmayın.
Nigel Thorne

@NigelThorne Cevabınız için teşekkürler. Yani örneğin bir URI ile bir kitap kimliği 10 PUT çalışıyorum: PUT kitaplar / 10. 10 numaralı kitap kimliği yoksa, 10 numaralı kimliğe sahip bir kitap oluşturmalıyım değil mi? ancak oluşturma kimliği payını kontrol edemiyorum, çünkü bu otomatik artış. bu durumda ne yapmalıyım?
Roni Axelrad

1
@RoniAxelrad Var olmayan bir kimliğe REST PUT, sunucunun bir kaynak oluşturma isteğidir. Buna izin vermek isteyip istemediğine hala sunucu karar verir. Sunucu sorumlu. "Hayır. Bunu yapmayacağım" şeklinde yanıt verebilir. Kullanıcının yeterli izinleri yoksa ... vb. Zaten bunu yapıyorsunuz. Sunucunun "Hayır" demesi sorun değil. REST, çeşitli istek türlerinin anlamını tanımlamamızı sağlayan bir kuraldır ... sunucunuz, iş mantığınıza dayalı olarak bu isteklerle ne yapacağına karar verir :) "Hayır" yazsa bile, hala REST'i takip eder :)
Nigel Thorne

38

Kısa cevap:

Basit kural: Oluşturmak için POST kullanın, güncellemek için PUT kullanın.

Uzun cevap:

İLETİ:

  • POST, sunucuya veri göndermek için kullanılır.
  • Kaynağın URL'si bilinmiyorsa kullanışlıdır

KOYMAK:

  • PUT, durumu sunucuya aktarmak için kullanılır
  • Bir kaynağın URL'si bilindiğinde kullanışlıdır

Daha Uzun Cevap:

Bunu anlamak için PUT'un neden gerekli olduğunu, PUT'un POST'un çözemediği sorunları neler olduğunu sormamız gerekiyor.

Bir REST mimarisi açısından önemli olan hiçbir şey yoktur. PUT olmadan da yaşayabilirdik. Ancak bir müşteri geliştiricinin bakış açısından hayatını çok daha basit hale getirdi.

PUT öncesinde, istemciler sunucunun oluşturduğu URL'yi veya bunların tümünü oluşturup oluşturmadığını veya sunucuya gönderilecek verilerin zaten güncellenip güncellenmediğini doğrudan bilemezlerdi. PUT, geliştiriciyi tüm bu baş ağrılarından kurtardı. PUT idempotent, PUT yarış koşullarını yönetir ve PUT istemcinin URL'yi seçmesine izin verir.


3
Kısa cevabınız ÇOK yanlış olabilir. HTTP PUT, HTTP proxy'leri tarafından yinelenebilir. Ve böylece, PUT aslında SQL INSERT yapıyorsa, ikinci kez başarısız olabilir, bu da farklı sonuç döndüreceği anlamına gelir ve bu yüzden IDEMPOTENT (PUT ve POST arasındaki farktır)
olmayacaktır

36

Ruby on Rails 4.0 kısmi güncellemeler yapmak için PUT yerine 'PATCH' yöntemini kullanacaktır.

RFC 5789, PATCH hakkında (1995'ten beri) şunları söylüyor:

Birlikte çalışabilirliği artırmak ve hataları önlemek için yeni bir yöntem gereklidir. PUT yöntemi, yeni bir gövdeye sahip bir kaynağın üzerine yazmak için zaten tanımlanmıştır ve kısmi değişiklikler yapmak için yeniden kullanılamaz. Aksi takdirde, proxy'ler ve önbellekler ve hatta istemciler ve sunucular işlemin sonucunda karışabilir. POST zaten kullanılıyor ancak geniş bir birlikte çalışabilirlik olmadan (bir tanesi için yama formatı desteğini keşfetmenin standart bir yolu yok). PATCH, daha önceki HTTP özelliklerinde belirtildi, ancak tam olarak tanımlanmadı.

" Edge Rails: PATCH, güncellemeler için yeni birincil HTTP yöntemidir " diye açıklıyor.


27

Zaten söz konusu olmuştur neyi restating riskini göze alarak, unutulmamalıdır görünüyor PUT hangi müşteri kontrolleri ima URL bir kaynak oluştururken sonuna kadar gidiyor, varlık. PUT ve POST arasındaki seçimin bir kısmı, URL düzeniniz ne olursa olsun, doğru, normalize edilmiş URL'yi sağlamak için istemciye ne kadar güvenebileceğiniz konusunda olacaktır .

Doğru şeyi yapmak için istemciye tam olarak güvenemiyorsanız, yeni bir öğe oluşturmak için POST'u kullanmak ve ardından URL'yi yanıtta istemciye geri göndermek daha uygun olacaktır .


2
Buna biraz geç kaldım - ama başka bir web sitesinde benzer bir şey söyleyen biri benim için tıklattı. Bir kaynak oluşturuyorsanız ve kullanıcı tarafından atanan ad yerine "tanımlayıcı" olarak otomatik olarak artırılan bir kimlik kullanıyorsanız, bunun bir POST olması gerekir.
Ixmatus

2
Bu tam olarak doğru değil - PUT hala yanıt olarak sürece bir kanonik olmayan adıyla kendisine atıfta bulunarak bir kaynak oluşturmak için, sunucu döndürür bir Locationbaşlık yok kurallı kaynak adını içerir.
Eter

1
@Joshcodes, aynı temel kaynağa başvuran birçok URI'nizin olabileceğini unutmayın. Ether'in söyledikleri sağlam bir tavsiyedir, istemci bir URL'ye (daha anlamsal olabilir) PUT yapabilir PUT /X-files/series/4/episodes/maxve sunucu yeni kaynağa (yani /X-Ffiles/episodes/91) kısa bir kanonik benzersiz bağlantı sağlayan bir URI ile yanıt verebilir
thecoshman

@ thecoshman sorun URL yapısı istemciye ait değil endişe. Kendini keşfetme (REST'in bir parçası) hakkında okumak bunu açıklığa kavuşturmaya yardımcı olabilir.
Joshcodes

@Joshcodes daha sonra bu mantıkla bir müşteri, URL'yi sağlamakla ilgilenmemesi gerektiği için PUT'u asla oluşturmak için kullanmamalıdır. Peki ... sunucu PUT'a bir URL vermediyse, istemci koymak istiyorsa ... "PUT / comments / new" gibi bir şey ve sunucu "204 / comments / 234532" şeklinde yanıt verebilir, ancak bu biraz görünüyor RPC bana, müşteri / POST sadece POST gerekir ...
thecoshman

24

Çok basit bir şekilde Facebook zaman çizelgesi örneğini alıyorum.

Durum 1: Zaman çizelgenize bir şey gönderdiğinizde, bu yeni ve yeni bir giriş. Bu durumda POST yöntemini kullanmazlar, çünkü POST yöntemi idempotent değildir.

Durum 2: Arkadaşınız postanıza ilk kez yorum yaparsa, bu da veritabanında yeni bir giriş oluşturur, böylece POST yöntemi kullanılır.

Durum 3: Arkadaşınız yorumunu düzenlerse, bu durumda yorum kimliği vardı, bu nedenle veritabanında yeni bir giriş oluşturmak yerine mevcut bir yorumu güncelleyecekler. Bu nedenle, bu tür bir işlem için, idempotent olduğu için PUT yöntemini kullanın. *

Tek bir satırda, veritabanına yeni bir giriş eklemek için POST'u ve veritabanındaki bir şeyi güncellemek için PUT'u kullanın .


4
Yorum, kullanıcı kimliği, oluşturulma tarihi, yorum mesajı vb. Özelliklere sahip bir nesne ise ve düzenleme sırasında yalnızca yorum mesajı güncelleniyorsa, PATCH burada mı yapılmalıdır?
Habeeb Perwad

PUT, mevcut bir kaynak güncellendiğinden FB tarafından yorumu güncellemek için kullanılır ve PUT bunu yapar (bir kaynağı günceller). PUT, POST'un aksine idempotent olur. Idempotent olan bir HTTP fiili hata işlemeyi etkiler, ancak kullanımı gerektirmez. Daha ayrıntılı bir açıklama için cevabımı görün: stackoverflow.com/questions/630453/put-vs-post-in-rest/…
Joshcodes

21

En önemli husus güvenilirliktir . Bir POST mesajı kaybolursa, sistemin durumu tanımsızdır. Otomatik kurtarma imkansızdır. PUT iletileri için, durum yalnızca ilk başarılı yeniden denemeye kadar tanımsızdır.

Örneğin, POST ile kredi kartı işlemleri oluşturmak iyi bir fikir olmayabilir.

Kaynağınızda otomatik olarak oluşturulmuş URI'larınız varsa, oluşturulan bir URI'yi (boş bir kaynağa işaret ederek) istemciye ileterek PUT'u kullanabilirsiniz.

Dikkat edilmesi gereken diğer noktalar:

  • POST, içerdiği tüm kaynağın önbelleğe alınmış kopyalarını geçersiz kılar (daha iyi tutarlılık)
  • POST yanıtları PUT yanıtları önbelleğe alınamaz (İçerik-Konum ve süre sonu gerektir)
  • PUT, örneğin Java ME, eski tarayıcılar, güvenlik duvarları tarafından daha az desteklenir

Bu yanlış. POST için, durum yalnızca ilk başarılı yeniden denemeye kadar tanımsızdır . Daha sonra, sunucu POST'u kabul eder (ileti hiç ulaşmadı), yinelenen bir kimlik için 409 çakışması atar (ileti geldi, yanıt kayboldu) veya başka bir geçerli yanıt.
Joshcodes

Genel olarak bir kullanıcı, POST işlemini güvenli bir şekilde yeniden deneyemez, çünkü POST işlemi iki işlemin biriyle aynı etkiye sahip olacağını garanti etmez. "Kimlik" teriminin HTTP ile ilgisi yoktur. URI kaynağı tanımlar.
Hans Malherbe

Bir kullanıcı bir POST işlemini istediği kadar "güvenli bir şekilde" yeniden deneyebilir. Yalnızca yinelenen bir kimlik hatası ( kaynağın bir kimliği olduğu varsayılarak ) veya yinelenen bir veri hatası (bunun bir sorun olduğunu ve kaynağın kimlikleri olmadığı varsayılarak ) alır.
Joshcodes

Kafa duvara vurur. HTTP'nin güvenilirlik sorununa bir çözümü yoktur ve bu iyi anlaşılmamıştır, fazla tartışılmamıştır ve web uygulamalarının büyük çoğunluğunda sunulmamaktadır. @Joshcodes Bu soruya bir cevabım var. Aslında Hans ile aynı fikirdeyim. Bir sorun var.
bbsimonbb

@bbsimonbb, HTTP'nin sağlam ve iyi belgelenmiş bir dizi hata yanıtı vardır. Bu soruya cevabım ( stackoverflow.com/questions/630453/put-vs-post-in-rest/… ) tutarlılığı sağlamak için http'nin spesifikasyona göre nasıl kullanılacağını kapsar.
Joshcodes

17

Bu konuyla ilgili yeni okuyucular, ne yapmanız gerektiği ve deneyimden derslerin göreceli yokluğu ile ilgili sonsuz tartışmadan etkilenecektir. REST'in SOAP'a göre "tercih edildiği" gerçeği, sanırım, deneyimden yüksek seviyeli bir öğrenme, ama oradan ilerlemiş olmamız gereken iyilik mi? Yıl 2016. Roy'un tezi 2000 yılındaydı. Ne geliştirdik? Eğlencelimiydi? Entegrasyonu kolay mıydı? Desteklemek? Akıllı telefonların ve kesintili mobil bağlantıların yükselişini ele alacak mı?

ME'ye göre, gerçek hayat ağları güvenilmez. İstek zaman aşımı. Bağlantılar sıfırlandı. Ağlar bir seferde saatler veya günler boyunca azalır. Trenler mobil kullanıcılarla tünellere giriyor. Herhangi bir talep için (zaman zaman tüm bu tartışmalarda kabul edildiği gibi), istek yolda suya düşebilir ya da yanıt geri dönerken suya düşebilir. Bu koşullarda, doğrudan önemli kaynaklara karşı PUT, POST ve DELETE istekleri yayınlamak beni her zaman biraz acımasız ve naif olarak etkiledi.

HTTP, istek yanıtının güvenilir bir şekilde tamamlanmasını sağlamak için hiçbir şey yapmaz ve bu sadece ağa duyarlı uygulamaların işi olduğundan iyidir. Böyle bir uygulama geliştirerek, POST yerine PUT kullanmak için çemberlerden atlayabilir, daha sonra yinelenen istekleri algılarsanız sunucuda belirli bir hata vermek için daha fazla çember yapabilirsiniz. Müşteriye geri döndüğünüzde, bu hataları yorumlamak, yeniden doldurmak, yeniden doğrulamak ve yeniden yayınlamak için çembere atlamanız gerekir.

Veya bunu yapabilirsiniz : güvensiz taleplerinizi geçici tek kullanıcılı kaynaklar olarak düşünün (onlara eylem diyelim). İstemciler, kaynak için boş bir POST bulunan önemli bir kaynak üzerinde yeni bir "işlem" ister. POST yalnızca bunun için kullanılacaktır. Yeni basılmış eylemin URI'sine güvenli bir şekilde sahip olduktan sonra, istemci hedef kaynağa değil, eylem URI'sına güvensiz bir istek koyar . Eylemin çözümlenmesi ve "gerçek" kaynağın güncellenmesi, API'nizin işidir ve burada güvenilir olmayan ağdan ayrılmıştır.

Sunucu işi yapar, yanıtı döndürür ve kararlaştırılan eylem URI'sında saklar . Bir şeyler ters giderse, istemci isteği tekrarlar (doğal davranış!) Ve sunucu zaten görmüşse, saklanan yanıtı tekrarlar ve başka bir şey yapmaz .

Benzerliği vaatlerle hızlı bir şekilde tespit edeceksiniz: herhangi bir şey yapmadan önce sonuç için yer tutucuyu oluşturup iade ediyoruz. Ayrıca bir söz gibi, bir eylem bir kez başarılı olabilir veya başarısız olabilir, ancak sonucu tekrar tekrar getirilebilir.

Hepsinden iyisi, gönderme ve alma uygulamalarına benzersiz olarak tanımlanmış eylemi kendi ortamlarındaki benzersizliğe bağlama şansı veriyoruz. Müşterilerden sorumlu davranış talep etmeye ve uygulamaya!

Bu nedenle, çok sayıda dikenli sorun ortadan kalkar. Tekrarlanan ekleme istekleri kopya oluşturmaz ve verilere sahip olana kadar gerçek kaynağı oluşturmayız. (veritabanı sütunları boş bırakılamaz). Tekrarlanan güncelleme istekleri uyumsuz durumlara ulaşmaz ve sonraki değişikliklerin üzerine yazmaz. Müşteriler, orijinal onayı herhangi bir nedenle (istemci çöktü, yanıt kayboldu vb.) Alabilir ve sorunsuz bir şekilde işleyebilir.

Art arda silme istekleri, 404 hatasına basmadan orijinal onayı görebilir ve işleyebilir. İşler beklenenden daha uzun sürerse, geçici olarak yanıt verebiliriz ve müşterinin kesin sonucu kontrol edebileceği bir yerimiz vardır. Bu desenin en güzel kısmı Kung-Fu (Panda) özelliğidir. Bir zayıflık, müşterilerin cevabı anlamadıklarında bir talebi tekrarlama eğilimi ve bunu bir güce dönüştürüyoruz :-)

Bana bunun RESTful olmadığını söylemeden önce, REST ilkelerine saygı duyulması gereken çeşitli yolları göz önünde bulundurun. İstemciler URL oluşturmaz. Anlambilimde küçük bir değişiklik olsa da API keşfedilebilir durumda kalır. HTTP fiilleri uygun şekilde kullanılır. Bunun uygulanması büyük bir değişiklik olduğunu düşünüyorsanız, size deneyimden olmadığını söyleyebilirim.

Saklamak için büyük miktarda veriye sahip olacağını düşünüyorsanız, hadi konuşalım: tipik bir güncelleme onayı kilobaytın bir kısmıdır. HTTP şu anda size kesin olarak yanıt vermeniz için bir iki dakika veriyor. İşlemleri yalnızca bir hafta boyunca saklasanız bile, müşterilerin yetişme şansı vardır. Çok yüksek hacimleriniz varsa, asitle uyumlu özel bir anahtar değeri deposu veya bellek içi bir çözüm isteyebilirsiniz.


1
Yanıt depolamak oturumu sürdürmek gibi olmayacak mı? Hangi (yatay) ölçeklendirme sorunlarına neden olur.
Saurabh Harwande

17

Başkaları tarafından önerilen farklılıklara ek olarak, bir tane daha eklemek istiyorum.

Gelen POST yöntemiyle size vücut params gönderebilirform-data

Gelen PUT yöntemiyle size vücut params göndermek zorundax-www-form-urlencoded

Başlık Content-Type:application/x-www-form-urlencoded

Buna göre PUT yönteminde dosya gönderemez veya çok parçalı veri gönderemezsiniz

DÜZENLE

"Application / x-www-form-urlencoded" içerik türü, büyük miktarlarda ikili veri veya ASCII olmayan karakterler içeren metin göndermek için yetersizdir. "Çok bölümlü / form verileri" içerik türü, dosyalar, ASCII olmayan veriler ve ikili veriler içeren formlar göndermek için kullanılmalıdır.

Bu, göndermek zorunda olduğunuz anlamına gelir

dosyalar, ASCII olmayan veriler ve ikili veriler

POST yöntemini kullanmalısınız


3
Bu neden iptal edilmedi? Eğer doğruysa, bu kritik bir ayrım değil mi?
Iofacture

2
Kullanıcı profili resim yüklemesini içeren profil güncellemesi için API uygularken bununla karşılaştım. Sonra postacı, Ajax, PHP curl ve laravel 5.6 ile arka uç olarak test ettim.
Rohit Dhiman

14

REST hizmetleri için HTTP PST ile HTTP PUT yönteminin ne zaman kullanılacağı konusunda her zaman bir karışıklık var gibi görünüyor. Çoğu geliştirici CRUD işlemlerini doğrudan HTTP yöntemleriyle ilişkilendirmeye çalışır. Bunun doğru olmadığını ve sadece CRUD kavramlarını HTTP yöntemleriyle ilişkilendiremeyeceğini iddia edeceğim. Yani:

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

CRUD işlemlerinin R (etrieve) ve D (elete) değerlerinin sırasıyla doğrudan GET ve DELETE HTTP yöntemleriyle eşleştirilebileceği doğrudur. Ancak, karışıklık C (reate) ve U (update) işlemlerinde yatmaktadır. Bazı durumlarda, PUT bir oluşturma için kullanılabilirken, diğer durumlarda bir POST gerekir. Belirsizlik, bir HTTP POST yöntemine karşı bir HTTP PUT yönteminin tanımında yatmaktadır.

HTTP 1.1 spesifikasyonlarına göre GET, HEAD, DELETE ve PUT yöntemlerinin idempotent olması ve POST yönteminin idempotent olmaması gerekir. Yani, bir işlem bir kaynak üzerinde bir veya birkaç kez gerçekleştirilebiliyorsa ve her zaman bu kaynağın aynı durumunu döndürüyorsa, idempotenttir. Ancak idempotent olmayan bir işlem, kaynağın değiştirilmiş bir durumunu bir istekten diğerine döndürebilir. Bu nedenle, idempotent olmayan bir işlemde, bir kaynağın aynı durumunu alacağının garantisi yoktur.

Yukarıdaki idempotent tanımına dayanarak, HTTP PUT yöntemini REST hizmetleri için HTTP POST yöntemini kullanmaya karşı almak benim:

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).

Her iki durumda da, bu işlemler aynı sonuçlarla birden çok kez gerçekleştirilebilir. Yani kaynak işlemi bir kereden fazla talep ederek değiştirilmeyecektir. Bu nedenle, gerçek bir idempotent operasyon. Aşağıdaki durumlarda HTTP POST yöntemini kullanın:

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.

Sonuç

CRUD işlemlerini REST hizmetleri için HTTP yöntemleriyle doğrudan ilişkilendirmeyin ve eşlemeyin. HTTP PUT yöntemine karşı HTTP POST yönteminin kullanılması, söz konusu işlemin idempotent yönüne dayanmalıdır. Yani, işlem idempotent ise, HTTP PUT yöntemini kullanın. İşlem idempotent değilse, HTTP POST yöntemini kullanın.


2
Güncelleme => HTTP POST: POST güncelleme için değil
Premraj

@premraj Burhan'ın yapmamanızı söylediğini varsaydınız; yani CRUD, REST ve HTTP'yi karıştırıyorsunuz. Bunların tanımlandığı RFC 7231'i okursanız, HTTP protokolünde POST tanımının kesinlikle güncellenmeye izin verdiğini göreceksiniz. Aksini söyleyen sadece REST'in kısıtlamalarıdır.
IAM_AL_X

13

kaynak sunucu bu URI ile kaynak oluşturabilir

Yani POST kullanın ve muhtemelen, ama kaynak oluşturmak için gerekli PUT. Her ikisini de desteklemek zorunda değilsiniz. Benim için POST yeterli. Yani bu bir tasarım kararı.

Alıntıda belirtildiği gibi, bir IRI'ye atanmış kaynak bulunmaması için PUT kullanırsınız ve yine de bir kaynak oluşturmak istersiniz. Örneğin, PUT /users/123/passwordgenellikle eski parolayı yenisiyle değiştirir, ancak henüz yoksa parola oluşturmak için kullanabilirsiniz (örneğin, yeni kaydedilmiş kullanıcılar veya yasaklı kullanıcıları geri yükleyerek).


Bence PUT'un nasıl kullanılacağına dair birkaç iyi örnekten birini sağlamayı başardınız, aferin.
thecoshman

12

Aşağıdakilerle ineceğim:

PUT, URI tarafından tanımlanan bir kaynağı ifade eder. Bu durumda, güncelliyorsunuz. Kaynaklara atıfta bulunan üç fiilin bir parçasıdır - sil ve diğer ikisi olmak.

POST, anlamı 'bant dışı' olarak tanımlandığı için, temelde bir serbest form mesajıdır. İleti bir dizine kaynak eklemek olarak yorumlanabilirse, sorun olmaz, ancak temel olarak kaynakta ne olacağını bilmek için gönderdiğiniz (gönderi) iletiyi anlamanız gerekir.


PUT ve GET ve DELETE bir kaynağa atıfta bulunduğundan, aynı zamanda idempotent tanımı gereğidir.

POST diğer üç işlevi yerine getirebilir, ancak daha sonra önbellek ve proxy gibi aracılarda talebin anlambilimi kaybolacaktır. Bu, bir kaynağın URI'sı uygulandığı kaynağı mutlaka belirtmediği için kaynakta güvenlik sağlamak için de geçerlidir (olsa da).

Bir PUT'un bir oluşturma olması gerekmez; kaynak önceden oluşturulmamışsa hizmet hata verebilir, ancak başka şekilde güncelleyin. Ya da tam tersi - kaynağı oluşturabilir, ancak güncellemelere izin vermez. PUT ile ilgili gereken tek şey, belirli bir kaynağa işaret etmesi ve yükünün o kaynağın temsil edilmesidir. Başarılı bir PUT, bir GET'in aynı kaynağı alacağı (engelleme etkileşimi) anlamına gelir.


Düzenleme: Bir şey daha - bir PUT oluşturabilir, ancak eğer o zaman kimliği doğal bir kimlik olmalıdır - AKA bir e-posta adresi. Bu şekilde iki kez koyduğunuzda, ikinci sıra ilkinin güncellemesidir. Bu onu cesaretsiz yapar .

Kimlik oluşturulursa (örneğin, yeni bir çalışan kimliği), aynı URL'ye sahip ikinci PUT, idempotent kuralını ihlal eden yeni bir kayıt oluşturur. Bu durumda fiil POST olur ve (kaynak değil) mesajı, bu mesajda tanımlanan değerleri kullanarak bir kaynak oluşturmak olacaktır.


9

Anlambilimin farklı olması gerekiyordu, çünkü "GET" gibi "PET" in idempotent olması gerekiyordu.

En yaygın ve en yararlı olduğunu düşündüğüm kuralları açıklayacağım:

Bir kaynağı belirli bir URL'ye koyduğunuzda, o URL'ye veya bu satırlardaki bir şeye kaydedilmesi gerekir.

Belirli bir URL'deki bir kaynağa POST yaptığınızda, genellikle bu URL'ye ilgili bir bilgi gönderirsiniz. Bu, URL'deki kaynağın zaten var olduğunu gösterir.

Örneğin, yeni bir akış oluşturmak istediğinizde, bunu bir URL'ye koyabilirsiniz. Ancak mevcut bir akışa ileti göndermek istediğinizde, URL'sine POST gönderirsiniz.

Akışın özelliklerini değiştirmeye gelince, bunu PUT veya POST ile yapabilirsiniz. Temel olarak, yalnızca işlem idempotent olduğunda "PUT" kullanın - aksi takdirde POST kullanın.

Ancak, tüm modern tarayıcıların GET veya POST dışındaki HTTP fiillerini desteklemediğini unutmayın.


POST'u aslında PATCH'in nasıl davranması gerektiği olarak tanımladığınız şey. POST'un, "posta listesine gönderme" bölümünde olduğu gibi "ekleme" ye daha benzer bir şey ifade etmesi gerekiyordu.
Alexander Torstling

8

Çoğu zaman, bunları şu şekilde kullanacaksınız:

  • POST bir koleksiyona bir kaynağı
  • Collection /: id ile tanımlanan bir kaynağı PUT

Örneğin:

  • POST / öğe
  • PUT / öğeler / 1234

Her iki durumda da, istek gövdesi oluşturulacak veya güncellenecek kaynağın verilerini içerir. POST'un idempotent olmadığı yol adlarından anlaşılmalıdır (3 kez çağırırsanız 3 nesne oluşturacaktır), ancak PUT idempotenttir (3 kez çağırırsanız sonuç aynıdır). PUT genellikle "upsert" işlemi (oluşturma veya güncelleme) için kullanılır, ancak yalnızca değiştirmek için kullanmak isterseniz her zaman bir 404 hatası döndürebilirsiniz.

POST'un koleksiyonda yeni bir öğe "oluşturduğunu" ve PUT'un belirli bir URL'deki bir öğeyi "değiştirdiğini" unutmayın, ancak kısmi değişiklikler için PUT'u kullanmak, yani yalnızca mevcut kaynakları güncellemek ve yalnızca gövdedeki alanları değiştirir (diğer alanları yoksayar). Bu teknik olarak yanlıştır, REST-purist olmak istiyorsanız, PUT kaynağın tamamını değiştirmeli ve kısmi güncelleme için PATCH kullanmalısınız. Kişisel olarak, tüm API uç noktalarınızda davranış açık ve tutarlı olduğu sürece umurumda değil.

Unutmayın, REST, API'nizi basit tutmak için bir dizi kural ve yönergedir. Eğer sadece "RESTfull" kutusunu işaretlemek için karmaşık bir çözümle karşılaşırsanız, o zaman amacı yenersiniz;)


7

Muhtemelen bunları tanımlamak için agnostik bir yol olsa da, web sitelerine verilen cevaplardan çeşitli ifadelerle çelişiyor gibi görünmektedir.

Burada çok net ve doğrudan olalım. Web API ile çalışan bir .NET geliştiricisiyseniz, gerçekler (Microsoft API belgelerinden), http://www.asp.net/web-api/overview/creating-web-apis/creating-a-web -api-that-supports-crud-işlemleri :

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

Tabii güncellemek için "POST" kullanabilirsiniz ", ancak sadece verilen çerçeve ile sizin için belirlenen kuralları izleyin. Benim durumumda .NET / Web API, bu nedenle PUT UPDATE için hiçbir tartışma yoktur.

Umarım bu, Amazon ve Sun / Java web sitesi bağlantılarıyla tüm yorumları okuyan herhangi bir Microsoft geliştiricisine yardımcı olur.


7

İşte basit bir kural:

Bir URL'ye PUT , o URL'de bulunabilecek kaynağı güncellemek veya oluşturmak için kullanılmalıdır.

Başka bir ("alt") URL'de bulunan veya HTTP aracılığıyla konumlandırılamayan bir kaynağı güncellemek veya oluşturmak için bir URL'ye POST kullanılmalıdır.


1
PUT güncelleme için değil, değiştirme içindir, oluşturmak için hiçbir şeyi bir şeyle değiştirmediğinizi unutmayın. POST kesinlikle herhangi bir formda güncelleme için değildir.
thecoshman

2
Http spec bunu söylüyor mu? Yoksa yorumunuzu başka bir şeye dayandırıyor musunuz?
Adam Griffiths

Bu sadece sağduyu, ne güncellediğinizi bilmediğinizde bir şeyi nasıl güncellersiniz? POST yeni bir kaynak oluşturmak içindir.
thecoshman

2
thecoshman - burada anlambilimi kötüye kullanıyorsunuz - bir değişiklik, aynı kaynak birkaç farklılığa sahipse bir güncelleme olabilir. Değiştirme yalnızca aynı kaynağı değiştirmek için değiştirme kullanılırsa put için geçerlidir. Özellikle 'yeni' kaynağın doğal bir kimliği yoksa, yeni ve farklı bir kaynakla değiştirmek geçersizdir (eski ve yeni eklensin mi?). POST, OTOH, oluşturabilen, güncelleyebilen, değiştirebilen ve silebilen bir şeydir - gönderiyi kullanmak, 'indirimi uygula' gibi yorumlanacak bir mesaj olup olmamasına bağlıdır, bu da kaynağa bağlı olarak değişebilir veya değişmeyebilir mantık.
Gerard ONeill

İkinci yorumunuza gelince - ya kaynağı 'almaya', ihtiyacınız olan alanları değiştirmeye ve sonra geri koymaya ne dersiniz? Ya da kaynağın farklı bir kaynaktan gelip doğal bir kimlik (harici kimlik) kullanıp kullanmadığı, put, orijinal veriler değiştiğinde URL'deki kaynağı doğal olarak güncelleyecektir.
Gerard ONeill

6

Veritabanı işlemlerini biliyorsanız,

  1. seçmek
  2. Ekle
  3. Güncelleme
  4. Sil
  5. Birleştir (Varsa güncelle, başka ekle)

Kullandığım PUTişlemleri ve kullanılması gibi birleştirme ve güncelleme için POSTinsersiyon için.


5

Pratikte POST, kaynak oluşturmak için iyi çalışır. Yeni oluşturulan kaynağın URL'si Konum yanıtı başlığında döndürülmelidir. Bir kaynağı tamamen güncellemek için PUT kullanılmalıdır. RESTful API tasarlarken bunların en iyi uygulamalar olduğunu lütfen unutmayın. HTTP belirtimi, kaynak oluşturmak / güncellemek için birkaç kısıtlamayla PUT / POST kullanımını kısıtlamaz. En iyi uygulamaları özetleyen http://techoctave.com/c7/posts/71-twitter-rest-api-dissected adresine bir göz atın .


Çoğunlukla, tüm bu gürültüyü okuyarak topun üzerinde görünüyorsunuz. Ama söyleyebilirim, biz oluşturma / güncelleme yerine yerine yöntem olarak PUT başvurmak gerekir. Bence ne yaptığını daha iyi tanımlıyor.
thecoshman
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.