Bir REST API, kısmen değiştirilebilir kaynaklara yönelik PUT isteklerini nasıl işlemelidir?


46

Bir HTTP GETisteğine yanıt olarak bir REST API'sinin, alt nesnede bazı ek veriler döndürdüğünü varsayalım owner:

{
  id: 'xyz',
  ... some other data ...
  owner: {
    name: 'Jo Bloggs',
    role: 'Programmer'
  }
}

Açıkçası, kimsenin PUTgeri dönmesini istemiyoruz.

{
  id: 'xyz',
  ... some other data ...
  owner: {
    name: 'Jo Bloggs',
    role: 'CEO'
  }
}

ve bunu başardı. Gerçekten de, muhtemelen, bu durumda, potansiyel olarak başarılı olmak için bunun bir yolunu bile uygulamayacağız .

Ancak bu soru sadece alt nesnelerle ilgili değil: Genel olarak, bir PUT isteğinde değiştirilemeyen verilerle ne yapılmalı?

PUT isteğindeki eksik olması gerekli mi?

Sessizce atılmalı mı?

Kontrol edilmeli ve bu özniteliğin eski değerinden farklıysa, yanıtta bir HTTP hata kodu döndürülsün mü?

Yoksa tüm JSON'u göndermek yerine RFC 6902 JSON yamalarını mı kullanmalıyız?


2
Bunların hepsi işe yarar. Sanırım gereksinimlerinize bağlı.
Robert Harvey,

En az sürpriz prensibinin PUT isteğinde eksik olması gerektiğini göstereceğini söyleyebilirim. Eğer mümkün değilse, kontrol edip farklı olup olmadığına bakın ve hata koduyla geri dönün. Sessiz atma en kötü yoldur (kullanıcı gönderiminin değişmesini beklediğini ve "200 Tamam" demişti).
Maciej Piechotka,

2
@MaciejPiechotka ile ilgili sorun, ekleme veya alma vb. İle aynı modeli kullanmayacaksınız, aynı modelin kullanılmasını tercih ederim ve basit bir alan için yetkilendirme kuralları olacaktır. değiştirilmemeleri gereken bir alan, 403 Yasağı geri aldılar ve daha sonra yetkilendirilirlerse izin verecek şekilde ayarlandılarsa, yetkilendirilmeleri durumunda 401 Yetkisiz hale getirilirler
Jimmy Hoffa

@JimmyHoffa: Modele göre veri formatını kastediyorsunuz (eğer kullanılıyorsa, seçimine bağlı olarak modeli MVC Rest çerçevesinde yeniden kullanmak mümkün olabilir - herhangi biri kullanılıyorsa - OP hiç bahsetmedi)? Çerçeve ile kısıtlama olmasaydım ve erken hatamın biraz daha keşfedilebilir / uygulanması kolay, sonra değişimi kontrol edersem keşfedilebilirlikle giderdim (tamam - XYZ alanına dokunmamalıyım). Her durumda, atma en kötüsüdür.
Maciej Piechotka 14:13

Yanıtlar:


46

W3C spesifikasyonunda veya REST'in resmi olmayan kurallarında, bir kuralın PUTaynı şema / modeli kullanması gerektiğine dair bir kural yoktur GET.

Onlar ne olduğunuz güzel benzer , fakat için alışılmadık bir durum değil PUTbiraz daha farklı şeyler yapmak. Örneğin, GETkolaylık sağlamak için, a tarafından döndürülen içeriğe bir tür kimlik içeren bir çok API gördüm . Ancak a ile PUTbu kimlik yalnızca URI tarafından belirlenir ve içerikte bir anlamı yoktur. Vücutta bulunan herhangi bir kimlik sessizce göz ardı edilir.

REST ve genel olarak web, Dayanıklılık İlkesine büyük ölçüde bağlıdır : "Yaptıklarınızda muhafazakar olun, [gönderdiğiniz], kabul ettiğiniz şeyler konusunda liberal olun." Felsefi olarak buna katılıyorsanız, çözüm açıktır: PUTİsteklerdeki geçersiz verileri yoksay . Bu, örneğinizde olduğu gibi hem değişken veriler hem de gerçek saçmalıklar, örneğin bilinmeyen alanlar için geçerlidir.

PATCHpotansiyel olarak başka bir seçenektir, ancak PATCHkısmi güncellemeleri gerçekten desteklemediğiniz sürece uygulamamalısınız . yalnızca içeriğe eklediğim belirli özellikleri güncellemePATCH anlamına gelir ; o mu değil demek tüm varlık yerine ancak bazı özel alanları hariç . Aslında bahsettiğiniz şey aslında kısmi bir güncelleme değil, tam bir güncelleme, belirsiz ve hepsi, sadece kaynağın salt okunur olması.

Bu seçeneği tercih ederseniz yapmanız gereken iyi bir şey , yanıtta asıl güncellenen varlık ile birlikte 200 (Tamam) geri göndermektir , böylece müşteriler salt okunur alanların güncellendiğini açıkça görebilirler.

Kesinlikle , başka yolla düşünen bazı insanlar var - bir kaynağın salt okunur bir bölümünü güncelleme girişiminin bir hata olması gerektiğini. Bunun için bazı gerekçeler var, öncelikle tüm kaynak salt okunur olsaydı ve kullanıcı onu güncellemeye çalıştıysa , kesinlikle bir hata döndürmeniz temelinde . Kesinlikle sağlamlık ilkesine aykırıdır, ancak API'nizin kullanıcıları için daha "kendi kendini belgeleyen" olduğunu düşünebilirsiniz.

Bunun için her ikisi de orijinal fikirlerine karşılık gelen iki sözleşme var, ama ben onları genişleteceğim. İlki, salt okunur alanların içerikte görünmesini yasaklamak ve varsa bir HTTP 400 (Kötü İstek) döndürmektir. Tanınmayan / kullanılamayan başka alanlar varsa, bu tür API'ler de bir HTTP 400 döndürmelidir. İkincisi, salt okunur alanların mevcut içerikle aynı olmasını ve değerler uyuşmuyorsa 409 (Çatışma) döndürmesini gerektirir.

Ben 409 ile eşitlik kontrolünden gerçekten hoşlanmıyorum, çünkü istemeden, GETyapmadan önce mevcut verileri almak için müşterinin yapmasını gerektirir PUT. Bu hiç hoş değil ve muhtemelen birileri için bir yerde düşük performansa yol açacak. Ben de bunun için 403'ü (Yasak) gerçekten sevmiyorum, çünkü tüm kaynağın sadece bir kısmı değil, korunduğunu ima ediyor . Bu yüzden, benim görüşüme göre, sağlamlık ilkesini takip etmek yerine kesinlikle doğrulamanız gerekiyorsa, tüm isteklerinizi doğrulayın ve fazladan ya da yazılamayan alanları olan herhangi bir kişi için 400'ü iade edin.

400/409 / belirli sorunun ne olduğu ve nasıl düzeltileceği hakkında bilgi içerenlerden emin olun.

Bu yaklaşımların her ikisi de geçerlidir, ancak birincisini sağlamlık ilkesine uygun olarak tercih ediyorum. Daha önce büyük bir REST API'si ile çalışmışsanız , geriye dönük uyumluluğun değerini takdir edeceksiniz. Var olan bir alanı kaldırmaya veya salt okunur hale getirmeye karar verirseniz, sunucu bu alanları görmezden gelirse ve eski istemciler hala çalışacaksa geriye dönük uyumlu bir değişikliktir. Ancak, içerik üzerinde kesin bir doğrulama yaparsanız, artık geriye dönük olarak uyumlu değildir ve eski müşteriler çalışmayı bırakacaktır. İlki, genel olarak hem API'nin sağlayıcısı hem de müşterileri için daha az iş anlamına gelir.


1
İyi cevap ve oy verildi. Ancak, bu konuda hemfikir olduğuma emin değilim: "Mevcut bir alanı kaldırmaya veya salt okunur hale getirmeye karar verirseniz, sunucu yalnızca bu alanları yoksayar ve eski istemciler hala çalışacaksa geriye dönük olarak uyumlu bir değişiklik olur. " Eğer müşteri bu kaldırılmış / sadece-salt okunur alana güveniyorsa, bunun hala uygulamanın genel davranışını etkilemeyebilir mi? Alanların kaldırılması durumunda, verileri dikkate almamak yerine açıkça bir hata oluşturmanın daha iyi olacağını savunuyorum; Aksi halde, müşteri önceden çalışan güncellemesinin şimdi başarısız olduğu hakkında hiçbir fikri yoktur.
Rinogo,

Bu cevap yanlış. RFC2616'dan 2 nedenden ötürü: 1. (bölüm 9.1.2) PUT bağımsız olmalıdır. Birçok kez koyun ve sadece bir kez koyarak aynı sonucu verecektir. 2. Bir kaynağa ulaşmak, kaynağı değiştirmek için başka bir istekte bulunulmamışsa, işletmeyi iade etmelidir
brunoais

1
Eşitlik kontrolü yaparsanız, sadece talepte değişmez değerin gönderilip gönderilmediğini kontrol edin. Bence bu size iki dünyanın en iyisini veriyor; müşterileri bir GET yapmaya zorlamıyorsunuz ve değişmez bir değer için geçersiz bir değer gönderdiklerinde hala bir şeylerin yanlış olduğunu bildiriyorsunuz.
Ahmad Abdelghany

Teşekkürler, deneyimden geçen son paragraflarda yaptığınız derinlemesine karşılaştırma tam olarak aradığım şeydi.
24'te dhill

9

Idem gücü

RFC'nin ardından, bir PUT kaynağa tam nesne teslim etmek zorunda kalacaktır. Bunun temel nedeni, PUT'un önemsiz olması gerektiğidir. Bu, tekrarlanan bir isteğin sunucuda aynı sonucu değerlendirmesi gerektiği anlamına gelir.

Kısmi güncellemelere izin verirseniz, artık etkili olamaz. Eğer iki müşteriniz varsa. Müşteri A ve B, ardından aşağıdaki senaryo gelişebilir:

Müşteri A kaynak resimlerden bir resim alır. Bu, görüntünün hala geçerli olan bir açıklamasını içerir. B müşterisi yeni bir görüntü ekler ve açıklamayı uygun şekilde günceller. Resim değişti. A İstemcisi görür, açıklamasını değiştirmek zorunda değildir, çünkü istediği gibidir ve yalnızca görüntüyü koyar.

Bu tutarsızlığa yol açacaktır, resmin üzerine yanlış meta veri eklenmiş!

Daha da fazla sinir bozucu olması, herhangi bir aracının talebi tekrar etmesi olabilir. Bir şekilde karar vermesi durumunda PUT başarısız oldu.

PUT'un anlamı değiştirilemez (yanlış kullanmanıza rağmen).

Diğer seçenekler

Neyse ki başka bir seçenek var, bu PATCH. PATCH, bir yapıyı kısmen güncellemenizi sağlayan bir yöntemdir. Kısmi bir yapı gönderebilirsiniz. Basit uygulamalar için bu iyi. Bu yöntem idem güçlü olduğu garanti edilmez. Müşteri, aşağıdaki şekilde bir istek göndermelidir:

PATCH /file.txt HTTP/1.1
Host: www.example.com
Content-Type: application/example
If-Match: "e0023aa4e"
Content-Length: 20
{fielda: 1, fieldc: 2}

Ve sunucu başarıyı işaretlemek için 204 (içerik yok) ile cevap verebilir. Hata durumunda yapının bir bölümünü güncelleyemezsiniz. PATCH metodu atomiktir.

Bu yöntemin dezavantajı, tüm tarayıcıların bunu desteklememesi, ancak bu bir REST hizmetindeki en doğal seçenektir.

Örnek yama isteği: http://tools.ietf.org/html/rfc5789#section-2.1

Json yaması

Json seçeneği oldukça kapsamlı ve ilginç bir seçenek gibi görünüyor. Ancak üçüncü şahıslar için uygulanması zor olabilir. Kullanıcı tabanınızın bunu yapıp yapamayacağına karar vermelisiniz.

Aynı zamanda biraz karmaşıktır, çünkü komutlarınızı modelinizi güncellemek için kullanacağınız kısmi bir yapıya dönüştüren küçük bir tercüman oluşturmanız gerekir. Bu tercüman ayrıca verilen komutların anlam ifade edip etmediğini de kontrol etmelidir. Bazı komutlar birbirini iptal eder. (fielda yaz, fielda sil). Sanırım, tarafındaki hata ayıklama süresini sınırlandırmak için bunu müşteriye geri rapor etmek istiyorsunuz.

Ancak zamanınız varsa, bu gerçekten zarif bir çözüm. Elbette ki alanları doğrulamalısınız. REST modelinde kalmak için bunu PATCH yöntemiyle birleştirebilirsiniz. Ancak POST'un burada kabul edilebilir olacağını düşünüyorum.

Kötü gidiyor

PUT seçeneği ile gitmeye karar verirseniz, bu biraz riskli. O zaman en azından hatayı atmamalısınız. Kullanıcının belli bir beklentisi vardır (veriler güncellenecektir) ve eğer bunu kırarsanız, bazı geliştiricilere iyi zaman vermeyeceksiniz.

Geri işaretlemeyi tercih edebilirsiniz: 409 Uyuşmazlık ya da 403 Yasak. Güncelleme işlemine nasıl baktığınıza bağlı. Bir dizi kural (sistem merkezli) olarak görürseniz, çatışma daha iyi olacaktır. Gibi bir şey, bu alanlar güncelleştirilebilir değil. (Kurallara aykırı). Bir yetkilendirme sorunu olarak görürseniz (kullanıcı merkezli), o zaman yasakla geri dönmelisiniz. Şunlarla: bu alanları değiştirme yetkiniz yok

Kullanıcıları hala tüm değiştirilebilir alanları göndermeye zorlamalısınız.

Bunu uygulamak için makul bir seçenek, yalnızca değiştirilebilir verileri sunan bir alt kaynağa ayarlamaktır.

Kişisel görüş

Şahsen basit PATCH modeli için (tarayıcılarla çalışmak zorunda kalmazsanız) gider ve daha sonra bir JSON yama işlemcisi ile genişletirim. Bu, mimetipleri farklılaştırarak yapılabilir: Mson tipi json yaması:

uygulama / json yama

Ve json: uygulama / json-patch

iki aşamada uygulamayı kolaylaştırır.


3
Idempotency örneğiniz mantıklı değil. Açıklamayı değiştirirsin ya da değiştirmezsin. Her iki durumda da, her seferinde aynı sonucu alırsınız.
Robert Harvey,

1
Haklısın, bence yatma vakti geldi. Düzenleyemiyorum. Bu, bir PUT isteğindeki tüm verilerin gönderilmesinin rasyonel olmasına bir örnektir. İşaretçi için teşekkürler.
Edgar Klerks,

Bunun 3 yıl önce olduğunu biliyorum ... ama RFC'de "PUT kaynağa tam bir nesne vermek zorunda kalacak" hakkında daha fazla bilgi bulabileceğimi biliyor musunuz? Bunu başka bir yerde bahsettiğimi gördüm ancak özelliklerinde nasıl tanımlandığını görmek istiyorum.
CSharper

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.