İstek Gövdesi'ni SİLMEK için RESTful Alternatifler


95

İken , HTTP 1.1 Spec görünüyor izin mesajı organları SİL istekleri, bunun için hiçbir tanımlanmış semantik olmadığından sunucular bunu görmezden gerektiğini belirtmek gibi görünüyor.

4.3 Mesaj Gövdesi

Bir sunucu, herhangi bir talep üzerine bir mesaj gövdesini okumalı ve iletmelidir; istek yöntemi bir varlık gövdesi için tanımlanmış anlambilim içermiyorsa, istek işlenirken ileti gövdesi göz ardı edilmelidir.

SO ve ötesinde bu konuyla ilgili birkaç ilgili tartışmayı zaten inceledim, örneğin:

Çoğu tartışma, bir DELETE üzerinde bir mesaj gövdesi sağlanmasına izin verilebileceği konusunda hemfikir görünmektedir , ancak genellikle önerilmez.

Ayrıca, çeşitli HTTP istemci kitaplıklarında, DELETE üzerindeki istek gövdelerini desteklemek için bu kitaplıklarda günlüğe kaydedilen daha fazla geliştirmenin olduğu bir eğilim fark ettim. Çoğu kütüphane, ara sıra biraz başlangıç ​​direncine rağmen, mecbur görünmektedir.

Kullanım durumum, bir DELETE üzerine bazı gerekli meta verilerin eklenmesini gerektiriyor (örneğin, silme için gerekli olan diğer bazı meta verilerle birlikte silme "nedeni"). Hiçbiri tamamen uygun görünmeyen ve HTTP spesifikasyonları ve / veya REST en iyi uygulamaları ile aynı hizada olan aşağıdaki seçenekleri değerlendirdim:

  • Mesaj Gövdesi - Spesifikasyon, DELETE üzerindeki mesaj gövdelerinin semantik değere sahip olmadığını belirtir; HTTP istemcileri tarafından tam olarak desteklenmez; standart uygulama değil
  • Özel HTTP Üstbilgileri - Özel üstbilgiler gerektirmek genellikle standart uygulamalara aykırıdır ; bunların kullanılması API'min geri kalanıyla tutarsızdır ve bunların hiçbiri özel başlık gerektirmez; ayrıca, kötü özel başlık değerlerini belirtmek için iyi bir HTTP yanıtı yok (muhtemelen tamamen ayrı bir soru)
  • Standart HTTP Üstbilgileri - Hiçbir standart üstbilgi uygun değildir
  • Sorgu Parametreleri - Sorgu parametrelerinin eklenmesi, silinen İstek-URI'sini değiştirir; standart uygulamalara karşı
  • POST Yöntemi - (örneğin POST /resourceToDelete { deletemetadata }) POST, silme için anlamsal bir seçenek değildir; POST aslında istenen zıt eylemi temsil eder (yani POST, kaynak astlarını oluşturur; ancak kaynağı silmem gerekiyor)
  • Çoklu Yöntemler - DELETE isteğini iki işleme bölmek (ör. PUT meta verileri silin, ardından SİL) atomik bir işlemi ikiye böler ve potansiyel olarak tutarsız bir durum bırakır. Silme nedeni (ve diğer ilgili meta veriler), kaynak temsilinin kendisinin bir parçası değildir.

İlk tercihim muhtemelen mesaj gövdesini kullanmak olacaktır, ikincisi özel HTTP başlıklarından sonra; ancak belirtildiği gibi, bu yaklaşımların bazı dezavantajları vardır.

DELETE isteklerine bu tür gerekli meta verileri dahil etmek için REST / HTTP standartlarına uygun herhangi bir öneri veya en iyi uygulama var mı? Düşünmediğim başka alternatifler var mı?


2
Gibi bazı uygulamalar istekler Jerseyiçin gövdeye izin vermez delete.
basiljames

Yanıtlar:


46

Mesaj gövdesinin DELETE istekleri için kullanılmaması yönündeki bazı tavsiyelere rağmen, bu yaklaşım belirli kullanım durumlarında uygun olabilir. Soru / cevaplarda belirtilen diğer seçenekleri değerlendirdikten ve hizmetin tüketicileriyle işbirliği yaptıktan sonra kullandığımız yaklaşım budur.

Mesaj gövdesinin kullanımı ideal olmasa da, diğer seçeneklerin hiçbiri de tam olarak uymuyordu. DELETE istek gövdesi, DELETE işlemine eşlik etmek için ihtiyaç duyulan ek veriler / meta veriler etrafında kolayca ve net bir şekilde anlambilim eklememize izin verdi.

Hala başka düşünceler ve tartışmalara açık olacaktım, ancak bu soruyla ilgili döngüyü kapatmak istedim. Bu konudaki herkesin düşüncelerini ve tartışmalarını takdir ediyorum!


12
Bu kötü bir fikir. Bunun başınızı belaya sokacağı yerlerden biri, daha sonra Akamai EdgeConnect gibi bir HTTP hızlandırma hizmetini kullanmaya karar vermenizdir. EdgeConnect'in gövdeleri HTTP DELETE isteklerinden çıkardığını biliyorum (bant genişliğini tükettikleri için muhtemelen geçersizdir). Benzer hizmetlerin de aynısını yapması muhtemeldir (Kindle'ın hızlandırma özelliğine ve diğer CDN benzeri hizmetlere bakın). Hizmetiniz için HTTP fiillerini kullanmamak için muhtemelen yeniden tasarlamalısınız. Çoğu API, HTTP-fiilleri / klasik-REST kullanarak çok az anlam ifade eder ve HTTP fiil taşıma sorunlarını gidermek çok zordur.
Gabe

3
@Gabe ile aynı fikirdeyim, tanım gereği gövdesi olmayan yöntemlerle bir gövde göndermek , bitleriniz internet borularından geçerken rastgele veri kaybetmek için kesin bir yoldur ve hata ayıklamakta çok zorlanacaksınız.
Nicholas Shanks

5
DELETE'in kullanımına yönelik bu yorumlar, OP'nin sahip olduğu çok geçerli konuları ele alıncaya kadar önemsizdir. REST ruhuna bağlı kalmak için elimden gelenin en iyisini yapmaya çalışıyorum, ancak iyimser eşzamanlılık olmadan silme ve atomik toplu işlem içermeyen bir silme, gerçek yaşam koşullarında pratik değildir. Bu, DİNLENME paterni ile ciddi bir eksikliktir.
Quarkly

1
Bu konuda @Quarkly ile birlikteyim. Eşzamanlılığı nasıl kontrol etmemiz gerektiği vb. Hakkındaki RESTFUL fikrinin ne olduğunu anlamıyorum. Eşzamanlılık kontrolleri istemciye ait değildir.
Dirk Wessels

13

Görünüşe göre istediğin şey, ikisi de saf olmayan iki şeyden biri DELETE:

  1. İki işleminiz var, bir PUTsilme nedeni ve ardından DELETEkaynağın a. Silindikten sonra, kaynağın içeriğine artık kimse erişemez. 'Neden', silinen kaynağa bir köprü içeremez. Veya,
  2. Bir kaynak değiştirmeye çalışıyoruz dan state=activehiç state=deletedkullanarak DELETEyöntemi. State = delete olan kaynaklar ana API'niz tarafından göz ardı edilir, ancak yine de bir yönetici veya veritabanı erişimi olan biri tarafından okunabilir. Buna izin verilir - DELETEbir kaynağın yedekleme verilerini silmek zorunda değildir, yalnızca o URI'de açığa çıkan kaynağı kaldırmak için.

Bir DELETEistek üzerine bir mesaj gövdesi gerektiren herhangi bir işlem , en genel haliyle, a POSTmesaj gövdesi ile gerekli tüm görevleri yapmak için ve a DELETE. HTTP'nin anlamını bozmak için bir neden göremiyorum.


3
Ne olur PUTsebebi başarılı ve DELETEkaynak başarısız? Tutarsız devlet nasıl önlenebilir?
Lightman

1
@Lightman, PUT yalnızca amacı belirtir. Birisinin silmek istediğini ancak başarısız olduğunu veya fikrini değiştirdiğini gösteren karşılık gelen bir DELETE olmadan var olabilir. Çağrıların sırasını tersine çevirmek ayrıca DELETE'lerin bir sebep olmaksızın gerçekleşmesine izin verir - bu durumda bir nedenin sağlanması yalnızca açıklama olarak kabul edilir. Bu iki nedenden ötürü yukarıdaki 2. seçeneği kullanmanızı tavsiye ederim, yani temel kaydın durumunu değiştirerek HTTP kaynağının mevcut URL'sinden kaybolmasına neden olur. Bir çöp toplayıcı / yönetici daha sonra kayıtları temizleyebilir
Nicholas Shanks

7

Sahip olduğunuz durum göz önüne alındığında, aşağıdaki yaklaşımlardan birini alırım:

  • Bir PUT veya PATCH gönder : Silme nedeninin doğası gereği, silme işleminin sanal olduğunu anlıyorum. Bu nedenle, kaydın bir PUT / PATCH işlemi aracılığıyla güncellenmesinin, başlı başına bir DELETE işlemi olmasa da geçerli bir yaklaşım olduğuna inanıyorum.
  • Sorgu parametrelerini kullanın : Kaynak uri değiştirilmiyor. Aslında bunun da geçerli bir yaklaşım olduğunu düşünüyorum. Bağladığınız soru, sorgu parametresi eksikse silmeye izin vermemekten bahsediyordu. Sizin durumunuzda, neden sorgu dizesinde belirtilmemişse sadece varsayılan bir nedenim olur. Kaynak yine de olacak resource/:id. Her neden için kaynakta Bağlantı başlıkları ile keşfedilebilir hale getirebilirsiniz (nedeni relbelirlemek için her birinin üzerinde bir etiket ile).
  • Her neden için ayrı bir uç nokta kullanın : Benzer bir url kullanma resource/:id/canceled. Bu aslında İstek URI'sını değiştirir ve kesinlikle RESTful değildir. Yine, bağlantı başlıkları bunu keşfedilebilir hale getirebilir.

REST'in kanun veya dogma olmadığını unutmayın. Bunu daha çok rehberlik olarak düşünün. Bu nedenle, sorunlu alanınız için yönergeleri takip etmemek mantıklı olduğunda, yapmayın. Sadece API tüketicilerinizin varyans hakkında bilgilendirildiğinden emin olun.


Sorgu parametrelerinin kullanımıyla ilgili olarak, benim anlayışım, sorgunun bölüm 3.2 başına İstek-URI'sinin bir parçası olduğu ve bu nedenle bu yaklaşımı (veya benzer şekilde, ayrı uç noktaları) kullanmanın DELETE yönteminin tanımına aykırı olduğu , öyle ki "kaynak İstek-URI tarafından tanımlanan "silinir.
shelley

Kaynak, uri yolu ile tanımlanır. Yani bir GET ile /orders/:idaynı kaynağı döndürür /orders/:id?exclude=orderdetails. Sorgu dizesi sunucuya yalnızca ipuçları veriyor - bu durumda yanıttaki sipariş ayrıntılarını hariç tutmak için (destekleniyorsa). Benzer şekilde, DELETE gönderiyorsanız /orders/:idveya /orders/:id?reason=canceledveya /orders/:id?reason=bad_credit, hala aynı temel kaynak üzerinde hareket ediyorsunuz. 'Tek tip bir arayüz' korumak için, sorgu parametresinin gönderilmesi gerekmemesi için varsayılan bir nedenim olacaktır.
codeprogression

@shelley Sorgu dizeleriyle ilgili endişelerinizde haklısınız. Sorgu dizesi URI'nin bir parçasıdır. Adresine bir DELETE isteği göndermek, DELETE göndereceğiniz /foo?123zamankinden farklı bir kaynağı sildiğiniz anlamına gelir /foo?456.
Nicholas Shanks

@codeprogression Üzgünüz, ama söylediklerinizin çoğu yanlış. Kaynak, yalnızca yol tarafından değil, tüm URI tarafından tanımlanır. Farklı sorgu dizeleri farklı kaynaklardır ('kaynak' kelimesinin HTTP anlamında). Ayrıca, tek tip bir arayüz için varsayılan bir neden gerekli değildir. Bu terim, GET, PUT, POST, PATCH ve DELETE'i HTTP tarafından tanımlandıkları şekilde kullanmayı ifade eder. Ortak nokta, satıcılar (kullanıcı aracısı satıcıları, API satıcıları, önbelleğe alma proxy satıcıları, ISP'ler vb.) Arasındadır ve kişinin kendi API'si içinde değildir (yine de bu, kullanıcılarının akıl sağlığı açısından tasarımda tek tip olmalıdır!).
Nicholas Shanks

@Nicholas Üç yıl önce sona eren bir tartışmayı tartışma ihtiyacınızı anlamıyorum. Yaptığım cevap ve yorumlar geçerli ve REST merkezli bir bakış açısına göre doğrudur. REST, HTTP (veya HTTP'nin herhangi bir satıcı uygulaması) değildir. REST bağlamında kaynaklar aynıdır. Ve cevabımda söylediğim gibi, REST kanun veya dogma değil, rehberliktir.
codeprogression

0

URI hiyerarşisinin bir parçası olarak gerekli meta verileri eklemenizi öneririm. Bir örnek (Naif):

Girişleri bir tarih aralığına göre silmeniz gerekiyorsa, başlangıç ​​tarihini ve bitiş tarihini gövdede veya sorgu parametreleri olarak geçirmek yerine, URI'yi, gerekli bilgileri URI'nin bir parçası olarak iletebileceğiniz şekilde yapılandırın.

Örneğin

DELETE /entries/range/01012012/31122012 - 01 Ocak 2012 ile 31 Aralık 2012 arasındaki tüm girişleri silin

Bu yardımcı olur umarım.


5
Silme nedeni gönderme gibi durumları, yani komisyon alanını kapsamaz.
Kugel

3
Vay. bu korkunç bir fikir. Çok fazla meta veriniz varsa, URI üzerindeki boyut kısıtlamalarını şişirecektir.
Balaji Boggaram Ramanarayan

1
Bu yaklaşım, RESTful uygulamalarını izlemez ve kıvrımlı bir URI yapısına sahip olacağınız için önerilmez. Uç noktalar, iç içe geçmiş kaynak tanımlama ve meta verilerle karıştırılır ve zamanla API'niz değiştikçe bir bakım kabusu haline gelir. rangeSorgu parametrelerinde veya yükte belirtilmiş olması çok daha çok tercih edilir ki bu sorunun özü: soruna en iyi uygulamaları anlamak için yaklaşımın bu olmadığını söyleyebilirim.
digitaldreamer

@digitaldreamer - Kıvrımlı URI yapısı derken neyi kastettiğinizi anlamıyorum? Ayrıca, bu bir HTTP DELETE'dir, dolayısıyla yük bir seçenek değil, sorgu parametreleri evettir.
Suresh Kumar
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.