วิธีที่เงียบสงบในการลบรายการจำนวนมาก


100

ในบทความวิกิสำหรับ REST ระบุว่าถ้าคุณใช้http://example.com/resources DELETE นั่นหมายความว่าคุณกำลังลบคอลเล็กชันทั้งหมด

หากคุณใช้http://example.com/resources/7HOU57Y DELETE นั่นหมายความว่าคุณกำลังลบองค์ประกอบนั้น

ฉันกำลังทำเว็บไซต์โปรดทราบว่าไม่ใช่บริการเว็บ

ฉันมีรายการที่มีช่องทำเครื่องหมาย 1 ช่องสำหรับแต่ละรายการในรายการ เมื่อฉันเลือกหลายรายการเพื่อลบฉันจะอนุญาตให้ผู้ใช้กดปุ่มที่เรียกว่า DELETE SELECTION หากผู้ใช้กดปุ่มกล่องโต้ตอบ js จะปรากฏขึ้นเพื่อขอให้ผู้ใช้ยืนยันการลบ หากผู้ใช้ยืนยันรายการทั้งหมดจะถูกลบ

ดังนั้นฉันจะจัดการกับการลบหลายรายการด้วยวิธี RESTFUL ได้อย่างไร?

หมายเหตุในปัจจุบันสำหรับการลบในหน้าเว็บเป็นสิ่งที่ผมทำคือผมใช้แท็กรูปแบบที่มีการโพสต์เป็นกระทำ แต่รวมถึง _method ด้วยค่าลบตั้งแต่นี้เป็นสิ่งที่ถูกระบุโดยคนอื่น ๆ ใน SO กับวิธีการทำสงบลบสำหรับหน้าเว็บ


1
จำเป็นหรือไม่ที่การลบเหล่านี้ต้องดำเนินการแบบอะตอม คุณต้องการย้อนกลับการลบ 30 รายการแรกหรือไม่ถ้าวันที่ 31 ไม่สามารถลบได้?
Darrel Miller

@darrelmiller คำถามที่ดี ฉันคิดว่าถ้าทำการลบแบบอะตอมมันจะมีประสิทธิภาพน้อยลง ดังนั้นฉันจึงเอนเอียงไปที่ DELETE FROM tablename WHERE ID IN ({list of ids}) หากมีใครสามารถชี้ให้ฉันเห็นว่านี่เป็นความคิดที่ดีหรือถูกต้อง ที่จะได้รับการชื่นชมอย่างดี นอกจากนี้ฉันไม่ต้องการการย้อนกลับของการลบสำหรับ 20 รายการแรกหากวันที่ 21 ถูกลบ ฉันขอขอบคุณอีกครั้งหากมีใครบางคนสามารถแสดงความแตกต่างในแนวทางที่ฉันต้องย้อนกลับกับจุดที่ฉันไม่จำเป็นต้องย้อนกลับ
Kim Stacks

1
หมายเหตุ: อาจมีข้อ จำกัด สำหรับอนุประโยค "IN"; ตัวอย่างเช่นใน Oracle คุณสามารถใส่รหัสได้สูงสุด 1,000 รหัส
ปล้น

คู่มือการออกแบบ API ของ Google นำเสนอโซลูชันในการสร้างการดำเนินการ (ชุดงาน) แบบกำหนดเองใน REST API ดูคำตอบของฉันที่นี่: stackoverflow.com/a/53264372/2477619
B12Toaster

คำตอบ:


54

ฉันคิดว่าคำตอบของ rojocaนั้นดีที่สุดแล้ว อาจมีการเปลี่ยนแปลงเล็กน้อยโดยใช้ javascript ยืนยันในหน้าเดียวกันและสร้างส่วนที่เลือกและเปลี่ยนเส้นทางไปยังข้อความยืนยันในหน้านั้นแทน กล่าวอีกนัยหนึ่ง:

จาก:
http://example.com/resources/

ทำ

โพสต์ด้วยการเลือก ID เพื่อ:
http://example.com/resources/selections

ซึ่งหากประสบความสำเร็จควรตอบสนองด้วย:

สร้าง HTTP / 1.1 201 และส่วนหัวตำแหน่งไปที่:
http://example.com/resources/selections/DF4XY7

ในหน้านี้คุณจะเห็นกล่องยืนยัน (javascript) ซึ่งหากคุณยืนยันจะทำตามคำขอของ:

ลบhttp://example.com/resources/selections/DF4XY7

ซึ่งหากสำเร็จควรตอบกลับด้วย: HTTP / 1.1 200 Ok (หรืออะไรก็ตามที่เหมาะสมสำหรับการลบที่สำเร็จ)


ฉันชอบแนวคิดนี้เพราะคุณไม่จำเป็นต้องเปลี่ยนเส้นทางใด ๆ การรวม AJAX เข้าด้วยกันคุณสามารถทำได้ทั้งหมดโดยไม่ต้องออกจากหน้า
rojoca

หลังจาก DELETE example.com/resources/selections/DF4XY7นี้ฉันจะถูกเปลี่ยนเส้นทางกลับไปที่ example.com/resources หรือไม่
Kim Stacks

7
@fireeyeboy วิธีการสองขั้นตอนนี้ดูเหมือนจะเป็นวิธีที่แนะนำโดยทั่วไปในการดำเนินการหลายลบ แต่ทำไม? ทำไมคุณไม่ส่งคำขอ DELETE ไปยัง uri like http://example.com/resources/selections/และใน payload (body) ของคำขอที่คุณส่งข้อมูลสำหรับรายการที่คุณต้องการลบ เท่าที่ฉันบอกได้ไม่มีอะไรขัดขวางคุณจากการทำเช่นนี้ แต่ฉันมักจะได้พบกับ "แต่มันไม่ใช่ RESTfull"
thecoshman

7
DELETE อาจทำให้เนื้อหาถูกละเว้นโดยโครงสร้างพื้นฐาน HTTP: stackoverflow.com/questions/299628/…
Luke Puplett

DELETE สามารถมีร่างกายได้ แต่การใช้งานจำนวนมากทำให้ร่างกายต้องห้ามโดยค่าเริ่มต้น
dmitryvim

54

ทางเลือกหนึ่งคือสร้าง "ธุรกรรม" ลบ ดังนั้นคุณจึงPOSTต้องการhttp://example.com/resources/deletesทรัพยากรใหม่ที่ประกอบด้วยรายการทรัพยากรที่จะลบ จากนั้นในแอปพลิเคชันของคุณคุณเพียงแค่ทำการลบ http://example.com/resources/deletes/DF4XY7เมื่อคุณทำโพสต์ที่คุณควรกลับที่ตั้งของเช่นทำธุรกรรมของคุณสร้างขึ้น สิ่งGETนี้สามารถส่งคืนสถานะของธุรกรรม (เสร็จสมบูรณ์หรืออยู่ระหว่างดำเนินการ) และ / หรือรายการทรัพยากรที่จะลบ


2
ไม่มีส่วนเกี่ยวข้องกับฐานข้อมูลของคุณ ตามธุรกรรมฉันหมายถึงรายการของการดำเนินการที่ต้องดำเนินการ ในกรณีนี้คือรายการลบ สิ่งที่คุณทำคือสร้างรายการใหม่ (ของการลบ) เป็นทรัพยากรในแอปพลิเคชันของคุณ เว็บแอปพลิเคชันของคุณสามารถประมวลผลรายการนั้นได้ตามที่คุณต้องการ ทรัพยากรที่มี URI เช่นexample.com/resources/deletes/DF4XY7 ซึ่งหมายความว่าคุณสามารถตรวจสอบสถานะของการลบผ่าน GET ไปยัง URI นั้นได้ สิ่งนี้จะเป็นประโยชน์หากเมื่อคุณทำการลบคุณต้องลบภาพจาก Amazon S3 หรือ CDN อื่น ๆ และการดำเนินการนั้นอาจใช้เวลานานกว่าจะเสร็จสมบูรณ์
rojoca

2
+1 นี่เป็นทางออกที่ดี แทนที่จะส่ง DELETE ไปยังทรัพยากรแต่ละรายการ @rojoca เสนอให้สร้างอินสแตนซ์ของทรัพยากรประเภทใหม่ที่มีงานเพียงอย่างเดียวคือการลบรายการทรัพยากร ตัวอย่างเช่นคุณมีคอลเล็กชันทรัพยากรผู้ใช้และคุณต้องการลบผู้ใช้ Bob, Dave และ Amy ออกจากคอลเล็กชันของคุณดังนั้นคุณจึงสร้างทรัพยากรการลบใหม่โดยโพสต์ Bob, Dave และ Amy เป็นพารามิเตอร์การสร้าง ทรัพยากรการลบถูกสร้างขึ้นและแสดงถึงกระบวนการแบบอะซิงโครนัสในการลบ Bob, Dave และ Amy จากคอลเล็กชันผู้ใช้
Mike Tunnicliffe

1
ฉันขอโทษ. ฉันยังคงมีปัญหาเล็กน้อยในการทำความเข้าใจบางประเด็น DF4XY7 คุณสร้างสตริงนี้ขึ้นมาบนโลกได้อย่างไร ทรัพยากรการลบนี้ ฉันจำเป็นต้องแทรกข้อมูลใด ๆ ลงในฐานข้อมูลหรือไม่? ฉันขอโทษถ้าฉันถามคำถามซ้ำ มันเป็นเพียงเล็กน้อยที่ไม่คุ้นเคยสำหรับฉัน
Kim Stacks

1
ฉันถือว่า DF4XY7 เป็นรหัสเฉพาะที่สร้างขึ้นบางทีอาจเป็นเรื่องธรรมดามากกว่าที่จะใช้ id ที่สร้างขึ้นเมื่อบันทึกลงในฐานข้อมูลเช่น example.com/resources/deletes/7 สิ่งที่ฉันทำคือการสร้างแบบจำลองการลบและบันทึกลงในฐานข้อมูลคุณสามารถให้กระบวนการแบบอะซิงโครนัสลบบันทึกอื่น ๆ จะอัปเดตโมเดลการลบด้วยสถานะความสมบูรณ์และข้อผิดพลาดที่เกี่ยวข้อง
Mike Tunnicliffe

2
@rojoca ใช่ฉันคิดว่าปัญหาคือ HTTP เป็นอย่างมาก 'DELETE สำหรับการลบทรัพยากรเดียว' สิ่งที่คุณเคยทำการลบหลายรายการเป็นเรื่องเล็กน้อย คุณยังสามารถส่งคืน "งาน" ให้กับลูกค้าได้โดยแจ้งว่างานนี้กำลังดำเนินการอยู่ (และอาจใช้เวลาสักครู่) แต่ใช้ URI นี้เพื่อตรวจสอบความคืบหน้า ฉันอ่านข้อมูลจำเพาะและรับว่า DELETE สามารถมีเนื้อความได้เช่นเดียวกับคำขออื่น ๆ
thecoshman

36

นี่คือสิ่งที่ Amazon ทำกับ S3 REST API

คำขอลบแต่ละรายการ:

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

คำขอลบหลายวัตถุ :

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>           

แต่Facebook Graph API , Parse Server REST APIและGoogle Drive REST APIไปได้ไกลกว่าเดิมด้วยการช่วยให้คุณสามารถ "แบทช์" การดำเนินการแต่ละรายการได้ในคำขอเดียว

นี่คือตัวอย่างจาก Parse Server

คำขอลบแต่ละรายการ:

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

คำขอเป็นกลุ่ม:

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

ผมจะบอกว่าลบhttp://example.com/resources/id1,id2,id3,id4หรือลบhttp://example.com/resources/id1+id2+id3+id4 เนื่องจาก "REST เป็นสถาปัตยกรรม (... ) [ไม่ใช่] โปรโตคอล" ที่จะอ้างถึงบทความวิกิพีเดียนี้ฉันเชื่อว่าไม่มีวิธีเดียวในการทำเช่นนี้

ฉันทราบว่าข้างต้นเป็นไปไม่ได้หากไม่มี JS กับ HTML แต่ฉันรู้สึกว่า REST คือ:

  • สร้างขึ้นโดยไม่คิดถึงรายละเอียดเล็กน้อยเช่นธุรกรรม ใครจะต้องดำเนินการในรายการเดียวมากกว่านั้น? นี่เป็นสิ่งที่ถูกต้องในโปรโตคอล HTTP เนื่องจากไม่ได้ตั้งใจที่จะให้บริการผ่านสิ่งอื่นใดจากหน้าเว็บคง
  • ไม่จำเป็นต้องปรับให้เข้ากับโมเดลปัจจุบัน - แม้แต่ HTML แท้

ขอบคุณ - จะเกิดอะไรขึ้นถ้าคุณต้องการลบทั้งคอลเลกชัน - ควรละ IDs หรือไม่?
BKSpurgeon

“ ฉันรู้สึกว่า REST ถูก ... สร้างขึ้นโดยไม่คิดถึงรายละเอียดเล็ก ๆ น้อย ๆ เช่นธุรกรรม” - ฉันไม่คิดว่ามันจะเป็นความจริง หากฉันเข้าใจถูกต้องใน REST ธุรกรรมจะแสดงโดยทรัพยากรไม่ใช่ด้วยวิธีการ มีบางสนทนาที่ดีเป็นที่ culminates ในความคิดเห็นนี้โพสต์บล็อกนี้
Paul D. Waite

10

ที่น่าสนใจคือฉันคิดว่าวิธีการเดียวกันนี้ใช้กับการจับคู่เอนทิตีหลายรายการและต้องคิดเกี่ยวกับความหมายของ URL พารามิเตอร์และวิธีการ REST

  1. ส่งคืนองค์ประกอบ 'foo' ทั้งหมด:

    [GET] api/foo

  2. ส่งคืนองค์ประกอบ 'foo' ด้วยการกรองรหัสเฉพาะ:

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

ในความหมายคือ URL และตัวกรองจะกำหนด "องค์ประกอบใดที่เรากำลังจัดการอยู่" และเมธอด REST (ในกรณีนี้คือ "GET") ระบุว่า "จะทำอย่างไรกับองค์ประกอบเหล่านั้น"

  1. ดังนั้น PATCH หลายระเบียนเพื่อทำเครื่องหมายว่าอ่านแล้ว

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

.. ด้วยข้อมูล foo [อ่าน] = 1

  1. ในที่สุดเพื่อลบหลายระเบียนจุดสิ้นสุดนี้มีเหตุผลมากที่สุด:

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

โปรดเข้าใจว่าฉันไม่เชื่อว่ามี "กฎ" ใด ๆ เกี่ยวกับเรื่องนี้ - สำหรับฉันแล้วมันแค่ "สมเหตุสมผล"


จริงๆแล้วเกี่ยวกับPATCH:เนื่องจากหมายถึงการอัปเดตบางส่วนหากคุณคิดเกี่ยวกับรายการของเอนทิตีเป็นเอนทิตีเอง (แม้ว่าจะเป็นประเภทอาร์เรย์) การส่งอาร์เรย์บางส่วน (เฉพาะรหัสที่คุณต้องการอัปเดต) ของเอนทิตีบางส่วนคุณ สามารถเว้นสตริงการสืบค้นได้ดังนั้นจึงไม่มี URL ที่แสดงถึงเอนทิตีมากกว่าหนึ่งรายการ
Szabolcs Páll

2

ในฐานะที่เป็นคุณค่าคำตอบที่จับโน่นฉวยและคำตอบ rojocasกล่าวว่าการที่ยอมรับมากที่สุดคือการใช้ทรัพยากรเสมือนการลบตัวเลือกของทรัพยากร แต่ผมคิดว่าไม่ถูกต้องจากมุมมองของ REST เพราะดำเนินการDELETE http://example.com/resources/selections/DF4XY7ควรเอาทรัพยากรที่ตัวเลือกของตัวเองไม่ได้ทรัพยากรที่เลือก

การใช้Maciej Piechotka anwserหรือคำตอบ fezfoxฉันมีเพียงการคัดค้าน: มีวิธีการส่งรหัสอาร์เรย์ที่เป็นที่ยอมรับมากขึ้นและใช้ตัวดำเนินการอาร์เรย์:

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

ด้วยวิธีนี้คุณกำลังโจมตีไปยังปลายทาง Delete Collection แต่กรองการลบด้วย Querystring อย่างถูกวิธี


-1

เนื่องจากไม่มีวิธีที่ 'เหมาะสม' ในการทำสิ่งนี้สิ่งที่ฉันเคยทำในอดีตคือ:

ส่ง DELETE ไปที่http://example.com/somethingโดยมีข้อมูลที่เข้ารหัส xml หรือ json ในเนื้อหา

เมื่อคุณได้รับคำขอให้ตรวจสอบ DELETE หากเป็นจริงจากนั้นอ่านเนื้อหาสำหรับรายการที่จะลบ


นี่เป็นวิธีการที่เหมาะสมสำหรับฉันคุณเพียงแค่ส่งข้อมูลในคำขอเดียว แต่ฉันมักจะได้พบกับ "แต่ไม่ใช่ RESTfull" คุณมีแหล่งข้อมูลใดบ้างที่แนะนำว่านี่เป็นวิธีที่ใช้ได้และ 'RESTfull' ในการทำสิ่งนี้หรือไม่?
thecoshman

11
ปัญหาของวิธีนี้คือการดำเนินการ DELETE ไม่ได้คาดหวังว่าจะมีเนื้อความดังนั้นเราเตอร์ระดับกลางบางตัวบนอินเทอร์เน็ตอาจลบออกให้คุณโดยที่คุณไม่ต้องควบคุม ดังนั้นการใช้ร่างกายเพื่อ DELETE จึงไม่ปลอดภัย!
Alex White

อ้างอิงความคิดเห็นของ Alex: 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.จากtools.ietf.org/html/rfc7231#section-4.3.5
cottton

-1

ฉันมีสถานการณ์เดียวกันในการลบหลายรายการ นี่คือสิ่งที่ฉันทำ ฉันใช้การดำเนินการ DELETE และรหัสของรายการที่จะลบเป็นส่วนหนึ่งของส่วนหัว HTTP

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.