Bir sürü öğeyi silmenin huzurlu yolu


100

In REST wiki makalesi bunu kullandığınız takdirde belirtilmektedir http://example.com/resources araçlarının tüm koleksiyonunu silme olduğunu, SİL.

Http://example.com/resources/7HOU57Y DELETE kullanırsanız , bu, o öğeyi sildiğiniz anlamına gelir.

WEB SİTESİ yapıyorum, WEB HİZMETİ DEĞİLDİR.

Listedeki her öğe için 1 onay kutusu olan bir listem var. Silmek için birden fazla öğe seçtiğimde, kullanıcıların SEÇİMİ SİL adlı bir düğmeye basmasına izin vereceğim. Kullanıcı düğmeye basarsa, bir js iletişim kutusu açılır ve kullanıcıdan silme işlemini onaylamasını ister. Kullanıcı onaylarsa tüm öğeler silinir.

Öyleyse, birden çok öğeyi RESTFUL bir şekilde silmeye nasıl hitap etmeliyim?

NOT, şu anda bir web sayfasında DELETE için yaptığım şey, eylem olarak POST ile FORM etiketini kullanıyorum, ancak bu, SO'da başkaları tarafından web sayfası için RESTful silme işleminin nasıl yapılacağıyla ilgili olarak belirtildiği için DELETE değerine sahip bir _metod eklemektir .


1
Bu silme işlemlerinin atomik olarak yapılması kritik mi? 31. öğe silinemezse, ilk 30 öğenin silinmesini gerçekten geri almak istiyor musunuz?
Darrel Miller

@darrelmiller güzel soru. Silinmeler atomik olarak yapılırsa daha az verimli olur diye düşündüm . Bu yüzden DELETE FROM tablename WHERE ID IN ({list of id}) konusuna eğiliyorum. Birisi bana bunun iyi bir fikir mi yoksa beni düzeltmek mi olduğunu söyleyebilir. bu çok takdir edilecektir. Ayrıca 21. öğe silinirse, ilk 20 öğe için silme işleminin tersini istemiyorum. Birisi bana tersine çevirmem gereken ve tersine çevirmem gerekmeyen yaklaşımdaki farklılığı gösterebilirse yine minnettarım
Kim Stacks

1
Not: "IN" yan tümcesi için sınırlar olabilir; örneğin, Oracle'da maksimum 1000 kimlik koyabilirsiniz.
soymak

Google'ın API tasarım kılavuzu, bir REST API'de özel (toplu) işlemler oluşturmak için bir çözüm sunar,
cevabıma

Yanıtlar:


55

Bence rojoca'nın cevabı şimdiye kadarki en iyisi. Javascript'in aynı sayfada onaylanmasını ortadan kaldırmak ve bunun yerine, o sayfada bir onay mesajı göstererek seçimi oluşturup ona yönlendirmek için küçük bir değişiklik olabilir. Diğer bir deyişle:

From:
http://example.com/resources/

yap

Aşağıdaki kimlik seçenekleriyle birlikte POST:
http://example.com/resources/selections

başarılı olursa şununla yanıt vermelidir:

HTTP / 1.1 201 oluşturuldu ve şu adrese bir Konum başlığı:
http://example.com/resources/selections/DF4XY7

Bu sayfada daha sonra bir (javascript) onay kutusu göreceksiniz, eğer onaylarsanız aşağıdakilerden bir istekte bulunacaktır:

Http://example.com/resources/selections/DF4XY7’yi SİL

başarılı olursa şu şekilde yanıt vermelidir: HTTP / 1.1 200 Ok (veya başarılı bir silme için uygun olanı)


Bu fikri beğendim çünkü yeniden yönlendirmeye ihtiyacınız yok. AJAX ile tüm bunları sayfadan ayrılmadan yapabilirsiniz.
rojoca

Bu SİLİN ornek.com/resources/selections/DF4XY7 işleminden sonra , ornek.com/resources'e geri yönlendirilir miyim?
Kim Stacks

7
@fireeyeboy Bu iki adımlı yaklaşım, çoklu silme işlemini gerçekleştirmenin yaygın olarak önerilen bir yolu gibi görünüyor, ama neden? Neden http://example.com/resources/selections/silmek istediğiniz verileri gönderdiğiniz talebin yükünde (gövdesinde) bir uri'ye basit bir SİLME isteği göndermiyorsunuz? Anladığım kadarıyla bunu yapmanıza engel olan hiçbir şey yok, ama her zaman "ama bu DİNLENME değil" ile karşılaşıyorum.
thecoshman

7
DELETE, potansiyel olarak vücudun HTTP altyapısı tarafından yok sayılmasına neden olabilir: stackoverflow.com/questions/299628/…
Luke Puplett

DELETE bir gövdeye sahip olabilir, ancak uygulamalarının çoğu varsayılan olarak gövdesini yasakladı
dmitryvim

54

Seçeneklerden biri, silme "işlemi" oluşturmaktır. Böylece , silinecek kaynakların bir listesinden oluşan yeni bir kaynak POSTgibi http://example.com/resources/deletesbir şeye . Ardından uygulamanızda silme işlemini yaparsınız. Gönderiyi yaptığınızda, oluşturduğunuz işlemin bir konumunu döndürmelisiniz, örn http://example.com/resources/deletes/DF4XY7. Bunun GETüzerine bir işlemin durumunu (tamamlandı veya devam ediyor) ve / veya silinecek kaynakların bir listesini döndürebilir.


2
Veritabanınızla hiçbir ilgisi yok. İşlem derken, gerçekleştirilecek işlemlerin bir listesini kastediyorum. Bu durumda, silinenlerin listesidir. Yaptığınız şey, uygulamanızda bir kaynak olarak yeni bir liste (silinen) oluşturmaktır. Web uygulamanız bu listeyi istediğiniz gibi işleyebilir. Bu kaynağın bir URI'si vardır, örneğin example.com/resources/deletes/DF4XY7 . Bu, söz konusu URI'ye GET yoluyla silme işleminin durumunu kontrol edebileceğiniz anlamına gelir. Silme işlemi yaptığınızda Amazon S3'ten veya başka bir CDN'den görüntüleri silmeniz gerekiyorsa ve bu işlemin tamamlanması uzun zaman alıyorsa, bu kullanışlı olacaktır.
rojoca

2
+1 bu güzel bir çözüm. @Rojoca, her kaynağa bir DELETE göndermek yerine, tek görevi bir kaynak listesini silmek olan yeni bir kaynak türünün bir örneğini oluşturmayı önerir. Örneğin, bir kullanıcı kaynakları koleksiyonunuz var ve Kullanıcılar Bob, Dave ve Amy'yi koleksiyonunuzdan silmek istiyorsunuz, bu nedenle oluşturma parametreleri olarak yeni bir Silme kaynağı POSTing Bob, Dave ve Amy oluşturursunuz. Silme kaynağı oluşturulur ve Bob, Dave ve Amy'nin Kullanıcılar koleksiyonundan eşzamansız silinme sürecini temsil eder.
Mike Tunnicliffe

1
Üzgünüm. Hala birkaç sorunu anlamakta biraz güçlük çekiyorum. DF4XY7. nasıl olur da bu dizgiyi yaratırsınız? Bu Silme kaynağı. Veritabanına herhangi bir veri eklemem gerekiyor mu? Bazı soruları tekrar edersem özür dilerim. Bana biraz yabancı geliyor.
Kim Stacks

1
DF4XY7'nin üretilmiş benzersiz bir kimlik olduğunu varsayıyorum, belki de yalnızca DB'ye kaydedildiğinde oluşturulan kimliği kullanmak daha doğaldır, örneğin example.com/resources/deletes/7. Benim alacağım, Silme modelini oluşturmak ve veritabanına kaydetmek, eşzamansız işlemin diğer kayıtları silerek Silme modelini tamamlanma durumu ve ilgili hatalarla güncellemesini sağlayabilirsiniz.
Mike Tunnicliffe

2
@rojoca evet, bence sorun HTTP çok fazla 'DELETE tek bir kaynağı kaldırmak içindir'. Ne yaparsan yap, birden çok silme işlemi yapmak biraz zor. İstemciye bu görevin üzerinde çalışıldığını (ve biraz zaman alabileceğini) söyleyen bir 'işi' yine de iade edebilirsiniz ancak ilerlemeyi kontrol etmek için bu URI'yi kullanın. Spesifikasyonu okudum ve DELETE'in diğer istekler gibi bir gövdeye sahip olabileceğini aldım.
thecoshman

36

İşte Amazon'un S3 REST API ile yaptığı şey.

Bireysel silme talebi:

DELETE /ObjectName HTTP/1.1
Host: BucketName.s3.amazonaws.com
Date: date
Content-Length: length
Authorization: authorization string (see Authenticating Requests (AWS Signature Version 4))

Çok Nesne Silme isteği:

POST /?delete HTTP/1.1
Host: bucketname.s3.amazonaws.com
Authorization: authorization string
Content-Length: Size
Content-MD5: MD5

<?xml version="1.0" encoding="UTF-8"?>
<Delete>
    <Quiet>true</Quiet>
    <Object>
         <Key>Key</Key>
         <VersionId>VersionId</VersionId>
    </Object>
    <Object>
         <Key>Key</Key>
    </Object>
    ...
</Delete>           

Ancak Facebook Graph API , Parse Server REST API ve Google Drive REST API , tek bir istekte bireysel işlemleri "toplu" hale getirmenizi sağlayarak daha da ileri gider.

İşte Ayrıştırma Sunucusundan bir örnek.

Bireysel silme talebi:

curl -X DELETE \
  -H "X-Parse-Application-Id: ${APPLICATION_ID}" \
  -H "X-Parse-REST-API-Key: ${REST_API_KEY}" \
  https://api.parse.com/1/classes/GameScore/Ed1nuqPvcm

Toplu istek:

curl -X POST \
  -H "X-Parse-Application-Id: ${APPLICATION_ID}" \
  -H "X-Parse-REST-API-Key: ${REST_API_KEY}" \
  -H "Content-Type: application/json" \
  -d '{
        "requests": [
          {
            "method": "POST",
            "path": "/1/classes/GameScore",
            "body": {
              "score": 1337,
              "playerName": "Sean Plott"
            }
          },
          {
            "method": "POST",
            "path": "/1/classes/GameScore",
            "body": {
              "score": 1338,
              "playerName": "ZeroCool"
            }
          }
        ]
      }' \
  https://api.parse.com/1/batch

13

DELETE http://example.com/resources/id1,id2,id3,id4 veya DELETE http://example.com/resources/id1+id2+id3+id4 diyebilirim . Bu Wikipedia makalesini alıntılamak için "REST bir mimari (...) [protokol değil]" olduğundan, bunu yapmanın tek bir yolu olmadığına inanıyorum.

Yukarıdakinin HTML ile JS olmadan mümkün olmadığının farkındayım, ancak REST'in şöyle olduğu hissine kapılıyorum:

  • İşlemler gibi küçük ayrıntılar düşünülmeden oluşturulur. Kimin tek bir öğeden daha fazla işlem yapması gerekir? Bu, statik web sayfalarından başka herhangi bir şey aracılığıyla sunulması amaçlanmadığı için HTTP protokolünde bir şekilde gerekçelendirilmiştir.
  • Mevcut modellere iyi uyum sağlamaya gerek yok - saf HTML bile.

thx - ya tüm koleksiyonu silmek isterseniz - kimlikler atlanmalı mı?
BKSpurgeon

"REST'in ... işlemler gibi küçük ayrıntıları düşünmeden yaratıldığı hissine kapılıyorum" - Bunun pek doğru olduğunu sanmıyorum. Doğru anlarsam, REST'te işlemler bir yöntemle değil kaynaklarla temsil edilir. Bu blog gönderisindeki bu yorumla sonuçlanan bazı iyi tartışmalar var .
Paul D. Waite

10

İlginç bir şekilde, aynı yöntemin birden fazla varlığı PATCHing için geçerli olduğunu ve URL, parametrelerimiz ve REST yöntemimizle ne demek istediğimizi düşünmeyi gerektirdiğini düşünüyorum.

  1. tüm 'foo' öğelerini döndür:

    [GET] api/foo

  2. belirli kimlikler için filtreleme ile 'foo' öğelerini döndür:

    [GET] api/foo?ids=3,5,9

Bu anlamda URL ve filtre, "hangi öğelerle uğraştığımızı" belirler ve REST yöntemi (bu durumda "GET") "bu öğelerle ne yapmalı?"

  1. Bu nedenle, okundu olarak işaretlemek için birden fazla kaydı YAMA

    [PATCH] api/foo?ids=3,5,9

..veri ile foo [oku] = 1

  1. Son olarak, birden çok kaydı silmek için, bu uç nokta en mantıklı olanıdır:

    [DELETE] api/foo?ids=3,5,9

Lütfen anlayın bunda herhangi bir "kural" olduğuna inanmıyorum - bana göre bu sadece "mantıklı"


Aslında PATCH ile ilgili olarak : Varlıkların listesini bir varlık olarak düşünürseniz (dizi türünde olsa bile) kısmi bir dizi (yalnızca güncellemek istediğiniz kimlikler) göndererek kısmi güncelleme anlamına geldiğinden, o zaman siz sorgu dizesini dışarıda bırakabilir, dolayısıyla birden fazla varlığı temsil eden bir URL'ye sahip olmaz.
Szabolcs Páll

2

As Terbiyeli Dabbler cevap ve rojocas cevap diyor, en kanonik kaynaklarının seçimi silmek için sanal kaynakları kullanarak, ama bir yürütme çünkü o, REST açısından yanlış olduğunu düşünüyorum DELETE http://example.com/resources/selections/DF4XY7seçim kaynak kendisi değildir seçilmiş kaynaklar kaldırmalısınız.

Maciej Piechotka yanıtlayıcısını veya fezfox yanıtını alarak, yalnızca bir itirazım var: Bir dizi kimliği geçirmenin daha kanonik bir yolu var ve dizi operatörünü kullanıyor:

DELETE /api/resources?ids[]=1a2b3c4d-5e6f-7a8b-9c0d-1e2f3a4b5c6d&ids[]=7e8f9a0b-1c2d-3e4f-5a6b-7c8d9e0f1a2b

Bu şekilde Koleksiyonu Sil uç noktasına saldırırsınız, ancak silme işlemini bir sorgu dizesiyle doğru şekilde filtrelersiniz.


-1

Bunu yapmanın 'uygun' bir yolu olmadığından, geçmişte yaptığım şey:

gövdede xml veya json kodlu verilerle http://example.com/something adresine DELETE gönderin .

İsteği aldığınızda, SİL seçeneğini işaretleyin, doğruysa, silinecekler için gövdeyi okuyun.


Bana mantıklı gelen yaklaşım bu, sadece verileri tek bir istekte gönderiyorsunuz, yine de her zaman "ama RESTfull" ile karşılaşıyorum. Bunu yapmak için bunun uygulanabilir ve 'DİNLENEN' bir yöntem olduğunu öne süren herhangi bir kaynağınız var mı?
thecoshman

11
Bu yaklaşımla ilgili sorun, DELETE işlemlerinin bir gövde beklememesidir ve bu nedenle internetteki bazı ara yönlendiriciler sizin kontrolünüz veya bilginiz olmadan onu sizin için kaldırabilir. Öyleyse SİLME için body kullanmak güvenli değildir!
Alex White

Alex'in yorumu için referans: stackoverflow.com/questions/299628/…
Luke Puplett

1
A payload within a DELETE request message has no defined semantics; sending a payload body on a DELETE request might cause some existing implementations to reject the request.from tools.ietf.org/html/rfc7231#section-4.3.5
cottton

-1

Birden çok öğeyi silmek için aynı durumu yaşadım. Sonunda yaptığım şey bu. DELETE işlemini kullandım ve silinecek öğelerin kimlikleri HTTP başlığının parçasıydı.

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.