ทางเลือกอื่นที่น่าสนใจในการลบคำขอเนื้อหา


95

แม้ว่าข้อมูลจำเพาะ HTTP 1.1ดูเหมือนจะอนุญาตเนื้อหาข้อความในคำขอDELETEแต่ดูเหมือนว่าจะระบุว่าเซิร์ฟเวอร์ควรละเว้นเนื่องจากไม่มีความหมายที่กำหนดไว้

4.3 เนื้อหาข้อความ

เซิร์ฟเวอร์ควรอ่านและส่งต่อเนื้อหาข้อความตามคำขอใด ๆ หากวิธีการร้องขอไม่รวมความหมายที่กำหนดไว้สำหรับเอนทิตี - เนื้อความควรละเว้นเนื้อหาข้อความเมื่อจัดการกับคำขอ

ฉันได้ตรวจสอบการอภิปรายที่เกี่ยวข้องหลายหัวข้อเกี่ยวกับ SO และอื่น ๆ แล้วเช่น:

การอภิปรายส่วนใหญ่ดูเหมือนจะเห็นพ้องต้องกันว่าอาจอนุญาตให้มีเนื้อหาข้อความใน DELETE ได้แต่โดยทั่วไปไม่แนะนำ

นอกจากนี้ฉันสังเกตเห็นแนวโน้มในไลบรารีไคลเอ็นต์ HTTP ต่างๆซึ่งดูเหมือนว่าจะมีการบันทึกการปรับปรุงมากขึ้นเรื่อย ๆ สำหรับไลบรารีเหล่านี้เพื่อรองรับเนื้อหาคำขอใน DELETE ห้องสมุดส่วนใหญ่ดูเหมือนจะบังคับแม้ว่าบางครั้งจะมีการต่อต้านเล็กน้อย

กรณีการใช้งานของฉันเรียกร้องให้เพิ่มข้อมูลเมตาที่จำเป็นบางอย่างใน DELETE (เช่น "เหตุผล" ในการลบพร้อมกับข้อมูลเมตาอื่น ๆ ที่จำเป็นสำหรับการลบ) ฉันได้พิจารณาตัวเลือกต่อไปนี้ซึ่งไม่มีตัวเลือกใดที่เหมาะสมและสอดคล้องกับข้อกำหนด HTTP และ / หรือแนวทางปฏิบัติที่ดีที่สุดของ REST:

  • Message Body - ข้อมูลจำเพาะระบุว่าเนื้อหาของข้อความบน DELETE ไม่มีค่าความหมาย ไคลเอ็นต์ HTTP ไม่ได้รับการสนับสนุนอย่างเต็มที่ ไม่ใช่แนวทางปฏิบัติมาตรฐาน
  • ที่กำหนดเองส่วนหัว HTTP - การกำหนดส่วนหัวที่กำหนดเองโดยทั่วไปกับมาตรฐานการปฏิบัติ ; การใช้พวกเขาไม่สอดคล้องกับส่วนที่เหลือของ API ของฉันซึ่งไม่ต้องใช้ส่วนหัวที่กำหนดเอง ยิ่งไปกว่านั้นไม่มีการตอบสนอง HTTP ที่ดีเพื่อระบุค่าส่วนหัวที่กำหนดเองที่ไม่ถูกต้อง (อาจเป็นคำถามแยกกันทั้งหมด)
  • ส่วนหัว HTTP มาตรฐาน - ไม่มีส่วนหัวมาตรฐานที่เหมาะสม
  • พารามิเตอร์การสืบค้น - การเพิ่มพารามิเตอร์แบบสอบถามจะเปลี่ยนคำขอ -URI ที่ถูกลบไป การปฏิบัติตามมาตรฐาน
  • วิธีการโพสต์ - (เช่นPOST /resourceToDelete { deletemetadata }) POST ไม่ใช่ตัวเลือกเชิงความหมายสำหรับการลบ POST แสดงถึงการกระทำตรงข้ามที่ต้องการ (เช่น POST สร้างผู้ใต้บังคับบัญชาทรัพยากร แต่ฉันต้องการลบทรัพยากร)
  • วิธีการหลายวิธี - การแยกคำขอ DELETE ออกเป็นสองการดำเนินการ (เช่น PUT ลบข้อมูลเมตาจากนั้น DELETE) จะแยกการดำเนินการอะตอมออกเป็นสองส่วนซึ่งอาจทำให้สถานะไม่สอดคล้องกัน เหตุผลในการลบ (และข้อมูลเมตาอื่น ๆ ที่เกี่ยวข้อง) ไม่ได้เป็นส่วนหนึ่งของการแสดงทรัพยากรเอง

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

มีคำแนะนำหรือแนวทางปฏิบัติที่ดีที่สุดที่สอดคล้องกับมาตรฐาน REST / HTTP สำหรับการรวมข้อมูลเมตาที่จำเป็นในคำขอ DELETE หรือไม่ มีทางเลือกอื่นที่ฉันไม่ได้พิจารณาหรือไม่?


2
การใช้งานบางอย่างเช่นJerseyไม่อนุญาตให้มีเนื้อหาสำหรับdeleteคำขอ
Basiljames

คำตอบ:


46

แม้จะมีคำแนะนำบางประการที่จะไม่ใช้เนื้อหาข้อความสำหรับคำขอ DELETE แต่วิธีนี้อาจเหมาะสมในการใช้งานบางกรณี นี่เป็นแนวทางที่เราใช้หลังจากประเมินตัวเลือกอื่น ๆ ที่กล่าวถึงในคำถาม / คำตอบและหลังจากร่วมมือกับผู้บริโภคบริการ

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

ฉันยังคงเปิดกว้างสำหรับความคิดและการอภิปรายอื่น ๆ แต่ต้องการปิดการวนซ้ำของคำถามนี้ ฉันขอขอบคุณสำหรับความคิดและการอภิปรายของทุกคนในหัวข้อนี้!


12
นี่เป็นความคิดที่ไม่ดี สถานที่หนึ่งที่จะทำให้คุณมีปัญหาคือหากคุณตัดสินใจใช้บริการเร่งความเร็ว HTTP เช่น Akamai EdgeConnect ในภายหลัง ฉันทราบข้อเท็จจริงว่า EdgeConnect ดึงเนื้อหาออกจากคำขอ HTTP DELETE (เนื่องจากการใช้แบนด์วิดท์อาจไม่ถูกต้อง) นอกจากนี้ยังมีแนวโน้มว่าบริการที่คล้ายกันจะทำเช่นเดียวกัน (ดูคุณลักษณะการเร่งความเร็วของ Kindle และบริการอื่น ๆ ที่คล้ายกับ CDN) คุณควรออกแบบใหม่เพื่อไม่ให้ใช้กริยา HTTP สำหรับบริการของคุณ API ส่วนใหญ่มีเหตุผลเพียงเล็กน้อยเมื่อใช้ปัญหาการส่งคำกริยา HTTP-verbs / classical-REST และ HTTP นั้นยากมากที่จะแก้ปัญหา
Gabe

3
ฉันเห็นด้วยกับ @Gabe การส่งเนื้อหาด้วยวิธีการที่ไม่มีเนื้อความตามคำจำกัดความเป็นวิธีที่แน่นอนในการสูญเสียข้อมูลแบบสุ่มเมื่อบิตของคุณเคลื่อนที่ไปตามท่ออินเทอร์เน็ตและคุณจะมีช่วงเวลาที่ยากลำบากในการแก้ไขข้อบกพร่อง
Nicholas Shanks

4
ความคิดเห็นเหล่านี้เกี่ยวกับการใช้ DELETE จะไม่เกี่ยวข้องจนกว่าจะแก้ไขปัญหาที่ถูกต้องที่ OP มี ฉันพยายามอย่างดีที่สุดที่จะยึดมั่นในจิตวิญญาณของ REST แต่การลบที่ไม่มีการทำงานพร้อมกันในแง่ดีและการลบที่ไม่มีการดำเนินการแบตช์อะตอมนั้นไม่สามารถใช้ได้จริงในสถานการณ์จริง นี่เป็นข้อบกพร่องที่ร้ายแรงกับรูปแบบ REST
Quarkly

1
ฉันกับ @Quarkly เกี่ยวกับเรื่องนี้ ฉันไม่เข้าใจว่าแนวคิด RESTFUL คืออะไรเกี่ยวกับวิธีที่เราควรตรวจสอบการทำงานพร้อมกัน ฯลฯ การตรวจสอบภาวะพร้อมกันไม่ได้เป็นของไคลเอนต์
Dirk Wessels

13

สิ่งที่คุณต้องการคือหนึ่งในสองสิ่งซึ่งไม่ใช่สิ่งที่บริสุทธิ์DELETE:

  1. คุณมีสองการดำเนินงานPUTในเหตุผลที่ลบตามมาด้วยDELETEของทรัพยากร เมื่อลบแล้วเนื้อหาของทรัพยากรจะไม่สามารถเข้าถึงได้โดยทุกคน 'เหตุผล' ไม่สามารถมีไฮเปอร์ลิงก์ไปยังทรัพยากรที่ถูกลบ หรือ,
  2. คุณกำลังพยายามเปลี่ยนทรัพยากรจากเป็นstate=activeถึงstate=deletedโดยใช้DELETEเมธอด ทรัพยากรที่มี state = ลบจะถูกละเว้นโดย API หลักของคุณ แต่อาจยังอ่านได้สำหรับผู้ดูแลระบบหรือผู้ที่มีสิทธิ์เข้าถึงฐานข้อมูล อนุญาต - DELETEไม่จำเป็นต้องลบข้อมูลสำรองของทรัพยากรเพียงเพื่อลบทรัพยากรที่เปิดเผยใน URI นั้น

ดำเนินการใด ๆ ซึ่งจะต้องมีเนื้อหาของข้อความในDELETEคำขอสามารถถูกทำลายลงไปที่มันเป็นโดยทั่วไปส่วนใหญ่POSTจะทำทุกงานที่จำเป็นกับร่างกายข้อความ, DELETEและ ฉันไม่เห็นเหตุผลที่จะทำลายความหมายของ HTTP


3
จะเกิดอะไรขึ้นหากPUTเหตุผลประสบความสำเร็จและDELETEทรัพยากรล้มเหลว? จะป้องกันสถานะที่ไม่สอดคล้องกันได้อย่างไร?
Lightman

1
@ Lightman the PUT ระบุเจตนาเท่านั้น สามารถมีอยู่ได้โดยไม่มีการลบที่เกี่ยวข้องซึ่งจะบ่งบอกว่ามีคนต้องการลบ แต่ล้มเหลวหรือเปลี่ยนใจ การย้อนกลับลำดับของการโทรจะทำให้ DELETE เกิดขึ้นโดยไม่มีเหตุผล - จากนั้นการให้เหตุผลจะถือว่าเป็นเพียงคำอธิบายประกอบเท่านั้น ด้วยเหตุผลทั้งสองนี้ฉันจึงขอแนะนำให้ใช้ตัวเลือกที่ 2 จากข้างต้นนั่นคือการเปลี่ยนสถานะของเรกคอร์ดพื้นฐานเช่นทำให้ทรัพยากร HTTP หายไปจาก URL ปัจจุบัน จากนั้นคนเก็บขยะ / ผู้ดูแลระบบสามารถล้างบันทึกได้
Nicholas Shanks

7

จากสถานการณ์ที่คุณมีฉันจะใช้วิธีใดวิธีหนึ่งต่อไปนี้:

  • ส่ง PUT หรือ PATCH : ฉันอนุมานได้ว่าการดำเนินการลบเป็นเสมือนโดยธรรมชาติของการต้องการเหตุผลในการลบ ดังนั้นฉันเชื่อว่าการอัปเดตระเบียนผ่านการดำเนินการ PUT / PATCH เป็นวิธีการที่ถูกต้องแม้ว่าจะไม่ใช่การดำเนินการ DELETE ต่อ se
  • ใช้พารามิเตอร์การสืบค้น : ทรัพยากร uri ไม่ได้รับการเปลี่ยนแปลง ฉันคิดว่านี่เป็นแนวทางที่ถูกต้องเช่นกัน คำถามที่คุณเชื่อมโยงกำลังพูดถึงการไม่อนุญาตให้ลบหากพารามิเตอร์การค้นหาหายไป ในกรณีของคุณฉันจะมีเหตุผลเริ่มต้นถ้าเหตุผลนั้นไม่ได้ระบุไว้ในสตริงข้อความค้นหา resource/:idทรัพยากรที่จะยังคงอยู่ คุณสามารถทำให้ค้นพบได้ด้วยส่วนหัวของลิงก์ในทรัพยากรด้วยเหตุผลแต่ละข้อ (โดยมีrelแท็กที่แต่ละข้อเพื่อระบุเหตุผล)
  • ใช้ปลายทางแยกต่างหากต่อเหตุผล : การใช้ URL resource/:id/canceledเช่น สิ่งนี้จะเปลี่ยน Request-URI จริง ๆ และไม่น่าสนใจอย่างแน่นอน อีกครั้งส่วนหัวของลิงก์สามารถทำให้ค้นพบได้

โปรดจำไว้ว่า REST ไม่ใช่กฎหมายหรือความเชื่อ คิดว่าเป็นแนวทางมากขึ้น ดังนั้นเมื่อเป็นเรื่องสมควรที่จะไม่ปฏิบัติตามคำแนะนำสำหรับโดเมนปัญหาของคุณอย่าทำ เพียงตรวจสอบให้แน่ใจว่าผู้บริโภค API ของคุณได้รับทราบถึงความแปรปรวน


เกี่ยวกับการใช้พารามิเตอร์แบบสอบถามความเข้าใจของฉันคือแบบสอบถามเป็นส่วนหนึ่งของ Request-URI ต่อส่วน 3.2ดังนั้นการใช้วิธีการนี้ (หรือในทำนองเดียวกันจุดสิ้นสุดที่แยกจากกัน) จะขัดแย้งกับนิยามของวิธีการDELETEเช่นที่ "ทรัพยากร ที่ระบุโดย URI คำขอ "ถูกลบ
shelley

ทรัพยากรถูกระบุโดยเส้นทาง uri ดังนั้น GET to /orders/:idจะส่งคืนทรัพยากรเดียวกันกับ/orders/:id?exclude=orderdetails. สตริงการสืบค้นเป็นเพียงการให้คำแนะนำแก่เซิร์ฟเวอร์ - ในกรณีนี้คือการยกเว้น orderdetails ในการตอบกลับ (หากรองรับ) ในทำนองเดียวกันหากคุณกำลังส่ง DELETE ไปยัง/orders/:idหรือ/orders/:id?reason=canceledหรือ/orders/:id?reason=bad_creditคุณยังคงดำเนินการกับทรัพยากรพื้นฐานเดียวกัน เพื่อให้ 'อินเทอร์เฟซที่เหมือนกัน' ฉันมีเหตุผลเริ่มต้นเพื่อให้ไม่จำเป็นต้องส่งพารามิเตอร์แบบสอบถาม
codeprogression

@shelley คุณอยู่ในข้อกังวลของคุณเกี่ยวกับสตริงการสืบค้น สตริงการสืบค้นเป็นส่วนหนึ่งของ URI ส่งคำขอลบเพื่อหมายความว่าคุณกำลังลบทรัพยากรที่แตกต่างกันกว่าถ้าคุณจะส่งไปลบ/foo?123 /foo?456
Nicholas Shanks

@codeprogression ขออภัย แต่สิ่งที่คุณพูดผิดมาก ทรัพยากรถูกระบุโดย URI ทั้งหมดไม่ใช่แค่เส้นทาง สตริงการสืบค้นที่แตกต่างกันเป็นทรัพยากรที่แตกต่างกัน (ในความหมายของ HTTP ของคำว่า 'ทรัพยากร') นอกจากนี้ยังไม่จำเป็นต้องใช้เหตุผลเริ่มต้นสำหรับอินเทอร์เฟซที่เหมือนกัน คำนั้นหมายถึงการใช้ GET, PUT, POST, PATCH และ DELETE ตามที่ HTTP กำหนดไว้ ความเหมือนกันระหว่างผู้ขาย (ผู้ขายตัวแทนผู้ใช้ผู้ขาย API การแคชผู้ขายพร็อกซี ISP ฯลฯ ) และไม่อยู่ใน API ของตัวเอง (แม้ว่าจะออกแบบให้เหมือนกันเพื่อความมีสติของผู้ใช้ก็ตาม!)
Nicholas Shanks

@Nicholas ฉันไม่เข้าใจความต้องการของคุณในการโต้แย้งการสนทนาที่จบลงเมื่อสามปีก่อน คำตอบและความคิดเห็นของฉันถูกต้องและถูกต้องจากมุมมอง REST เป็นศูนย์กลาง REST ไม่ใช่ HTTP (หรือผู้ขายใช้ HTTP) ในบริบทของ REST ทรัพยากรจะเหมือนกัน และอย่างที่ฉันพูดในคำตอบของฉัน REST ไม่ใช่กฎหมายหรือความเชื่อ แต่เป็นแนวทาง
codeprogression

0

ฉันขอแนะนำให้คุณรวมข้อมูลเมตาที่จำเป็นเป็นส่วนหนึ่งของลำดับชั้น URI เอง ตัวอย่าง (ไร้เดียงสา):

หากคุณต้องการลบรายการตามช่วงวันที่แทนที่จะส่งวันที่เริ่มต้นและวันที่สิ้นสุดในเนื้อความหรือเป็นพารามิเตอร์การค้นหาให้จัดโครงสร้าง URI ในลักษณะที่คุณส่งผ่านข้อมูลที่ต้องการเป็นส่วนหนึ่งของ URI

เช่น

DELETE /entries/range/01012012/31122012 - ลบรายการทั้งหมดระหว่างวันที่ 1 มกราคม 2555 ถึง 31 ธันวาคม 2555

หวังว่านี่จะช่วยได้


5
ไม่ครอบคลุมกรณีต่างๆเช่นการส่งเหตุผลในการลบเช่นฟิลด์ commment
Kugel

3
ว้าว. นั่นเป็นความคิดที่แย่มาก หากคุณมีข้อมูลเมตามากเกินไปมันจะขยายข้อ จำกัด ขนาดใน URI
Balaji Boggaram Ramanarayan

1
วิธีนี้ไม่เป็นไปตามแนวทางปฏิบัติที่เป็นประโยชน์และไม่แนะนำเนื่องจากคุณจะมีโครงสร้าง URI ที่ซับซ้อน Endpoints ยุ่งเหยิงกับการระบุทรัพยากรที่เกี่ยวพันกับข้อมูลเมตาและในเวลาต่อมาจะกลายเป็นฝันร้ายในการบำรุงรักษาเมื่อ API ของคุณเปลี่ยนไป เป็นที่ต้องการมากกว่าที่จะrangeระบุไว้ในพารามิเตอร์แบบสอบถามหรือเพย์โหลดซึ่งเป็นเนื้อของคำถามนี้: เพื่อทำความเข้าใจแนวทางปฏิบัติที่ดีที่สุดในการแก้ไขปัญหาซึ่งฉันจะบอกว่าไม่ใช่สิ่งนี้
digitaldreamer

@digitaldreamer - ฉันไม่เข้าใจว่าคุณหมายถึงอะไรโดยโครงสร้าง URI ที่ซับซ้อน? นอกจากนี้นี่คือ HTTP DELETE ดังนั้นเพย์โหลดจึงไม่ใช่ตัวเลือก แต่พารามิเตอร์การค้นหาใช่
Suresh Kumar
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.