ลบหลายระเบียนโดยใช้ REST


100

REST-ful วิธีการลบหลายรายการคืออะไร?

กรณีการใช้งานของฉันคือฉันมี Backbone Collection ซึ่งฉันต้องสามารถลบหลายรายการพร้อมกันได้ ตัวเลือกดูเหมือนจะเป็น:

  1. ส่งคำขอ DELETE สำหรับทุกๆระเบียน (ซึ่งดูเหมือนจะเป็นความคิดที่ไม่ดีหากมีหลายสิบรายการ)
  2. ส่ง DELETE โดยที่ ID ที่จะลบจะถูกรวมเข้าด้วยกันใน URL (เช่น "/ records / 1; 2; 3");
  3. ด้วยวิธีที่ไม่ใช่ REST ให้ส่งออบเจ็กต์ JSON ที่กำหนดเองซึ่งมี ID ที่ทำเครื่องหมายสำหรับการลบ

ตัวเลือกทั้งหมดน้อยกว่าอุดมคติ

ดูเหมือนว่าจะเป็นพื้นที่สีเทาของการประชุม REST


3
วิธีที่เป็นไปได้ที่จะทำซ้ำในการลบรายการจำนวนมาก
Luka Žitnik

คำตอบ:


93
  1. เป็นทางเลือกที่น่าสนใจ แต่มีข้อ จำกัด ที่คุณได้อธิบายไว้อย่างชัดเจน
  2. อย่าทำอย่างนี้ ตัวกลางจะถูกตีความโดยสื่อความหมายว่า "ลบทรัพยากร (เดียว) ที่/records/1;2;3" ดังนั้นการตอบสนอง 2xx ต่อสิ่งนี้อาจทำให้พวกเขาล้างแคชของ/records/1;2;3; ไม่ได้ล้าง/records/1, /records/2หรือ/records/3; พร็อกซีการตอบสนอง 410 สำหรับ/records/1;2;3หรือสิ่งอื่น ๆ ที่ไม่สมเหตุสมผลจากมุมมองของคุณ
  3. ทางเลือกนี้ดีที่สุดและสามารถทำได้อย่างสงบ หากคุณกำลังสร้าง API และต้องการอนุญาตให้มีการเปลี่ยนแปลงทรัพยากรจำนวนมากคุณสามารถใช้ REST เพื่อดำเนินการได้ แต่จะไม่ชัดเจนในทันทีสำหรับหลาย ๆ คน วิธีหนึ่งคือสร้างทรัพยากร 'คำขอเปลี่ยนแปลง' (เช่นโดยการโพสต์เนื้อหาเช่นrecords=[1,2,3]ถึง/delete-requests) และสำรวจทรัพยากรที่สร้างขึ้น (ระบุโดยLocationส่วนหัวของการตอบกลับ) เพื่อดูว่าคำขอของคุณได้รับการยอมรับปฏิเสธอยู่ระหว่างดำเนินการหรือไม่ หรือเสร็จสิ้น สิ่งนี้มีประโยชน์สำหรับการดำเนินการที่ยาวนาน อีกวิธีหนึ่งคือการส่งPATCHคำขอไปยังทรัพยากรรายการ ,/recordsซึ่งเนื้อหาประกอบด้วยรายการทรัพยากรและการดำเนินการในทรัพยากรเหล่านั้น (ในรูปแบบใดก็ตามที่คุณต้องการสนับสนุน) สิ่งนี้มีประโยชน์สำหรับการดำเนินการอย่างรวดเร็วโดยที่รหัสตอบกลับสำหรับคำขอสามารถระบุผลลัพธ์ของการดำเนินการได้

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

อย่าลืมว่า REST ไม่ใช่วิธีเดียวในการแก้ปัญหาใด ๆ “ REST” เป็นเพียงรูปแบบสถาปัตยกรรมและคุณไม่จำเป็นต้องยึดติดกับมัน (แต่คุณจะสูญเสียประโยชน์บางประการของอินเทอร์เน็ตหากคุณไม่ทำ) ฉันขอแนะนำให้คุณดูรายชื่อสถาปัตยกรรม HTTP API นี้และเลือกสิ่งที่เหมาะกับคุณ เพียงแค่ตระหนักถึงสิ่งที่คุณสูญเสียไปหากคุณเลือกสถาปัตยกรรมอื่นและตัดสินใจอย่างชาญฉลาดตามกรณีการใช้งานของคุณ

มีคำตอบที่ไม่ดีสำหรับคำถามนี้เกี่ยวกับรูปแบบสำหรับการจัดการการดำเนินการแบทช์ในบริการเว็บ REST? ซึ่งมีการโหวตมากเกินไป แต่ก็ควรอ่านด้วย


2
ไม่ใช่เซิร์ฟเวอร์ของคุณที่คุณต้องกังวลเป็นตัวกลาง CDN แคชพร็อกซี ฯลฯ อินเทอร์เน็ตเป็นระบบแบบเลเยอร์ นั่นคือเหตุผลที่มันทำงานได้ดี Roy พิจารณาว่าด้านใดของระบบที่จำเป็นต่อความสำเร็จและตั้งชื่อให้ REST หากคุณDELETEส่งคำขอสิ่งใดก็ตามที่อยู่ระหว่างผู้ร้องขอและเซิร์ฟเวอร์จะคิดว่าทรัพยากรเดียวที่ URL ที่ระบุกำลังถูกลบ สตริงการสืบค้นเป็นส่วนทึบแสงของ URL ไปยังอุปกรณ์เหล่านี้ดังนั้นจึงไม่สำคัญว่าคุณจะระบุ API ของคุณอย่างไรพวกเขาไม่ได้เป็นส่วนหนึ่งของความรู้นี้จึงไม่สามารถทำงานได้แตกต่างกัน
Nicholas Shanks

3
/ records / 1; 2; 3 จะไม่ทำงานหากคุณมีทรัพยากรจำนวนมากในการลบเนื่องจากข้อ จำกัด ด้านความยาว URI
dukethrash

3
โปรดทราบว่าหากพิจารณา DELETE และเนื้อหาที่กำหนดทรัพยากรที่จะกำจัดตัวกลางบางตัวอาจไม่ส่งต่อเนื้อหา นอกจากนี้ไคลเอ็นต์ HTTP บางตัวไม่สามารถเพิ่มเนื้อหาใน DELETE ดูstackoverflow.com/questions/299628/…
Luke Puplett

3
@LukePuplett ฉันจะระบุว่าการส่งเนื้อหาDELETEคำร้องขอเป็นสิ่งต้องห้าม อย่าทำ ถ้าคุณทำฉันจะกินลูกของคุณ Nom nom.
Nicholas Shanks

3
ปัญหาในการโต้แย้งสำหรับ # 3 คือมีบทลงโทษเช่นเดียวกับการโต้แย้งโต้แย้งกับ # 2 การสร้างทรัพยากรเพื่อลบไม่ใช่สิ่งที่พร็อกซีต้นน้ำจะรู้วิธีจัดการ - อาร์กิวเมนต์ตอบโต้เดียวกันกับที่ยกขึ้นเทียบกับแนวทาง # 2
LB2

16

หากGET /records?filteringCriteriaส่งคืนอาร์เรย์ของระเบียนทั้งหมดที่ตรงกับเกณฑ์ก็DELETE /records?filteringCriteriaสามารถลบระเบียนดังกล่าวทั้งหมดได้

ในกรณีนี้คำตอบสำหรับคำถามของคุณDELETE /records?id=1&id=2&id=3คือ


1
ฉันได้ข้อสรุปนี้เช่นกัน: เพียงแค่พลิกคำกริยาไปที่สิ่งที่คุณต้องการทำ ฉันไม่เข้าใจว่าสิ่งที่เกิดขึ้นสำหรับ GET ไม่ได้เป็นไปเพื่อ DELETE
Luke Puplett

9
GET /records?id=1&id=2&id=3ไม่ได้หมายความว่า“ รับข้อมูลสามรายการด้วย ID 1, 2 & 3” แต่หมายถึง“ รับทรัพยากรเดียวที่มีเส้นทาง / ระเบียน URL? id = 1 & id = 2 & id = 3” ซึ่งอาจเป็นภาพหัวผักกาดเป็นข้อความธรรมดา เอกสารที่มีหมายเลข "42" เป็นภาษาจีนหรืออาจไม่มีอยู่
Nicholas Shanks

พิจารณาสิ่งต่อไปนี้: คำขอตามลำดับสองรายการสำหรับ/records?id=1และ/records?id=2ถูกส่งและคำตอบที่แคชไว้โดยตัวกลางบางอย่าง (เช่นเบราว์เซอร์หรือ ISP ของคุณ) หากอินเทอร์เน็ตรู้ว่าแอปพลิเคชันของคุณหมายถึงสิ่งนี้แสดงว่ามีเหตุผลที่/records?id=1&id=2แคชสามารถส่งคืนได้โดยการรวม (อย่างใดอย่างหนึ่ง) ผลลัพธ์ทั้งสองที่มีอยู่แล้วโดยไม่ต้องถามเซิร์ฟเวอร์ต้นทาง แต่นี่เป็นไปไม่ได้ /records?id=1&id=2อาจไม่ถูกต้อง (อนุญาตเพียง 1 ID ต่อคำขอ) หรืออาจส่งคืนสิ่งที่แตกต่างไปจากเดิมอย่างสิ้นเชิง (หัวผักกาด)
Nicholas Shanks

นี่เป็นปัญหาการแคชทรัพยากรพื้นฐาน หาก DBA ของฉันเปลี่ยนสถานะโดยตรงแสดงว่าแคชไม่ซิงค์กัน คุณให้ตัวอย่าง 410 ที่ตัวกลางส่งคืน แต่ 410 ใช้สำหรับการลบถาวรเมื่อ DELETE แคชอาจล้างช่องของ URL นั้น แต่จะไม่ส่ง 410 หรือ 404 เนื่องจากไม่ทราบว่า DBA ไม่เพียงแค่นำทรัพยากรกลับมาที่จุดเริ่มต้นทันที
Luke Puplett

4
@NicholasShanks ฉันไม่เห็นด้วยจริงๆ หากผลลัพธ์ถูกแคชนั่นเป็นความผิดพลาดของเซิร์ฟเวอร์ และหากคุณกำลังพูดถึงการออกแบบ API คุณหวังว่าจะเป็นคนที่เขียนโค้ดสำหรับเซิร์ฟเวอร์ ไม่ว่าคุณจะใช้id[]=1&id[]=2หรือid=1&id=2ในสตริงคิวรีเพื่อแสดงอาร์เรย์ของค่าสตริงคิวรีนั้นจะแทนค่านั้น และฉันคิดว่าเป็นเรื่องธรรมดามากและเป็นแนวทางปฏิบัติที่ดีที่จะให้สตริงการสืบค้นเป็นตัวแทนของตัวกรอง นอกจากนี้หากคุณอนุญาตให้ลบและอัปเดตอย่าแคชGETคำขอ หากคุณทำเช่นนั้นไคลเอนต์จะมีสถานะเก่า
Joseph Nields

10

ฉันคิดว่า Mozilla Storage Service SyncStorage API v1.5 เป็นวิธีที่ดีในการลบหลายระเบียนโดยใช้ REST

ลบคอลเล็กชันทั้งหมด

DELETE https://<endpoint-url>/storage/<collection>

ลบ BSO หลายรายการจากคอลเล็กชันด้วยคำขอเดียว

DELETE https://<endpoint-url>/storage/<collection>?ids=<ids>

ids : ลบ BSO ออกจากคอลเลกชันที่มีรหัสที่อยู่ในรายการที่คั่นด้วยจุลภาคที่ระบุ สามารถระบุได้สูงสุด 100 รหัส

ลบ BSO ในตำแหน่งที่กำหนด

DELETE https://<endpoint-url>/storage/<collection>/<id>

http://moz-services-docs.readthedocs.io/en/latest/storage/apis-1.5.html#api-instructions


นี่ดูเหมือนเป็นทางออกที่ดี ฉันเดาว่า mozilla คิดว่าถูกต้องแล้วมันต้องเป็นอย่างไร? คำถามเดียวคือการจัดการข้อผิดพลาด สมมติว่าผ่าน? ids = 1,2,3 และ id 3 ไม่มีอยู่คุณลบ 1 และ 2 จากนั้นตอบกลับด้วย 200 เนื่องจากผู้ร้องขอต้องการให้ 3 หายไปและไม่มีจึงไม่สำคัญ? หรือจะเกิดอะไรขึ้นถ้าพวกเขาได้รับอนุญาตให้ลบ 1 แต่ไม่ใช่ 2 ... คุณจะลบอะไรเลยและตอบกลับด้วยข้อผิดพลาดหรือคุณลบสิ่งที่คุณทำได้และปล่อยให้คนอื่น ๆ ...
tempcke

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

3

ดูเหมือนว่าจะเป็นพื้นที่สีเทาของการประชุม REST

ใช่เพื่อให้ห่างไกลฉันมีเพียงเจอคู่มือการออกแบบ REST API ที่กล่าวถึงการดำเนินงานชุด (เช่นชุดลบ) ที่: คู่มือการออกแบบ API ของ Google

คู่มือนี้กล่าวถึงการสร้างเมธอด "กำหนดเอง" ที่สามารถเชื่อมโยงผ่านรีซอร์สโดยใช้โคลอนเช่นhttps://service.name/v1/some/resource/name:customVerbยังกล่าวถึงการดำเนินการแบตช์อย่างชัดเจนเป็นกรณีการใช้งาน:

วิธีการที่กำหนดเองสามารถเชื่อมโยงกับทรัพยากรคอลเลกชันหรือบริการ อาจต้องใช้คำขอโดยพลการและตอบกลับโดยพลการและยังรองรับคำขอสตรีมและการตอบกลับ [ ... ] วิธีการที่กำหนดเองควรใช้ HTTP POST กริยาเพราะมันมีความหมายความยืดหยุ่นมากที่สุด [ ... ] สำหรับวิธีการที่สำคัญประสิทธิภาพก็อาจจะเป็นประโยชน์ที่จะให้วิธีการแบทช์ที่กำหนดเองเพื่อลดค่าใช้จ่ายต่อการร้องขอ

ดังนั้นคุณสามารถทำสิ่งต่อไปนี้ตามคู่มือ api ของ Google:

POST /api/path/to/your/collection:batchDelete

... เพื่อลบรายการทรัพยากรคอลเลกชันของคุณจำนวนมาก


เป็นวิธีการแก้ปัญหาที่มีการสื่อสารรายการผ่านอาร์เรย์ที่จัดรูปแบบ JSON หรือไม่
Daniele

แน่นอน. คุณสามารถโพสต์เพย์โหลดซึ่งรหัสถูกส่งผ่านอาร์เรย์ json
B12Toaster

เป็นเรื่องน่าสนใจที่คู่มือ API ของ Google กล่าวIf the HTTP verb used for the custom method does not accept an HTTP request body (GET, DELETE), the HTTP configuration of such method must not use the body clause at all,ไว้ที่บทวิธีการที่กำหนดเอง แต่ GET accounts.locations.batchGetapi คือ GET method กับ body นั่นเป็นเรื่องแปลก Developers.google.com/my-business/reference/rest/v4/…
鄭元傑

@ 鄭元傑เห็นด้วยดูแปลก ๆ เมื่อแรกเห็น แต่ถ้าคุณมองใกล้ ๆ มันเป็นPOSTวิธี http ที่ใช้และมีเพียงวิธีการที่กำหนดเองbatchGetเท่านั้น ฉันเดาว่า Google ทำเพื่อ (ก) ยึดติดกับกฎของพวกเขาที่ต้องใช้วิธีการที่กำหนดเองทั้งหมดPOST(ดูคำตอบของฉัน) และ (b) เพื่อให้ผู้คนใส่ "ตัวกรอง" ในเนื้อหาได้ง่ายขึ้นดังนั้นคุณจึงไม่ต้อง หลบหนีหรือเข้ารหัสตัวกรองเช่นเดียวกับสตริงการค้นหา ข้อเสียแน่นอนว่านี่ไม่สามารถแคชได้อีกต่อไป ...
B12Toaster

https://service.name/v1/some/resource/name:customVerbไม่น่าอยู่ตามคำจำกัดความ
deamon

2

ฉันอนุญาตให้มีการเปลี่ยนคอลเลกชันขายส่งเช่นPUT ~/people/123/shoesกรณีที่ร่างกายเป็นตัวแทนของคอลเลกชันทั้งหมด

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

ซึ่งหมายความว่าGET ~/people/123/shoes/9จะยังคงอยู่ในแคชแม้ว่า PUT จะลบออก แต่นั่นเป็นเพียงปัญหาการแคชและจะเป็นปัญหาหากมีบุคคลอื่นลบรองเท้า

API ข้อมูล / ระบบของฉันใช้ ETags เสมอเมื่อเทียบกับเวลาหมดอายุดังนั้นเซิร์ฟเวอร์จึงเข้าชมในแต่ละคำขอและฉันต้องการเวอร์ชัน / ส่วนหัวพร้อมกันที่ถูกต้องเพื่อเปลี่ยนข้อมูล สำหรับ API ที่เป็นแบบอ่านอย่างเดียวและจัดตำแหน่งมุมมอง / รายงานฉันจะใช้เวลาหมดอายุเพื่อลดการเข้าชมต้นทางเช่นลีดเดอร์บอร์ดใช้ได้ดีเป็นเวลา 10 นาที

สำหรับคอลเลกชันที่ใหญ่กว่ามากเช่น~/peopleฉันมักไม่ต้องการการลบหลายครั้งกรณีการใช้งานมีแนวโน้มที่จะไม่เกิดขึ้นตามธรรมชาติดังนั้น DELETE เดียวจึงทำงานได้ดี

ในอนาคตและจากประสบการณ์ในการสร้าง REST API และการแก้ไขปัญหาและข้อกำหนดเดียวกันเช่นการตรวจสอบฉันมีแนวโน้มที่จะใช้เฉพาะคำกริยา GET และ POST และออกแบบตามเหตุการณ์เช่น POST การเปลี่ยนแปลงที่อยู่แม้ว่าฉันจะสงสัยว่า จะมาพร้อมกับชุดปัญหาของตัวเอง :)

ฉันยังอนุญาตให้นักพัฒนาส่วนหน้าสร้าง API ของตนเองซึ่งใช้ API ส่วนหลังที่เข้มงวดขึ้นเนื่องจากมักจะมีเหตุผลที่ใช้ได้จริงและถูกต้องจากฝั่งไคลเอ็นต์ว่าทำไมพวกเขาจึงไม่ชอบการออกแบบ REST API แบบ "Fielding zealot" ที่เข้มงวดและเพื่อประสิทธิภาพและ เหตุผลในการแบ่งชั้นแคช


ฉันชอบคำตอบนี้มากจนกระทั่งฉันอ่านประโยคสุดท้าย :) ฉันไม่เคยเห็นกรณีการใช้งานที่การใช้ REST ที่เข้มงวดมีผลเสียสุทธิ แน่นอนว่าสามารถเขียนโค้ดได้มากขึ้นที่ปลายทั้งสองข้าง แต่คุณจะได้ระบบที่ปลอดภัยกว่าสะอาดกว่าและมีคู่น้อยกว่า
Nicholas Shanks

ฮ่า ๆ . มันกลายเป็นแพทเทิร์นจริงๆ! แบ็กเอนด์สำหรับส่วนหน้าเรียกว่าเรดาร์ของเทคโนโลยี ThoughtWorks นอกจากนี้ยังช่วยให้สามารถเขียนตรรกะของแอปพลิเคชันได้มากขึ้นซึ่งจะยุ่งยากในการพูด JavaScript และเห็นได้ชัดว่าสามารถอัปเดตได้โดยไม่ต้องมีไคลเอ็นต์ดังนั้นให้อัปเดตสำหรับแอป iOS
Luke Puplett

สกิมอ่านฮิตสี่ครั้งแรกจาก Google มันก็ดูเหมือนว่าเทคนิค BFF นี้สามารถทำงานเมื่อลูกค้าที่อยู่ภายใต้การควบคุมของคุณ นักพัฒนาไคลเอ็นต์จะพัฒนา API ที่ต้องการโดยทำการแมปการเรียกไปยัง microservice API ซึ่งเป็นแบ็คเอนด์ที่แท้จริง ในแผนภาพนี้: samnewman.io/patterns/architectural/bff/#bffฉันจะวางเส้น "ปริมณฑล" ไว้ใต้กล่อง BFF - แต่ละกล่องเป็นเพียงส่วนหนึ่งของไคลเอนต์ มันอาจอยู่นอกศูนย์ข้อมูลที่มีไมโครเซอร์วิส ฉันยังไม่เห็นว่า REST ใช้ไม่ได้กับทั้งสองอินเทอร์เฟซอย่างไร (ไคลเอนต์ / BFF และ BFF / ไมโครเซอร์วิส)
Nicholas Shanks

1
ใช่นั่นเป็นจุดที่ดี โดยปกติแล้วเมื่อคุณมีไมโครเซอร์วิสสำหรับการสร้างทีมและทีมที่สร้างแอพเชิงมุมและทีมนักพัฒนานั้นเป็นประเภทส่วนหน้ามากกว่าที่ไม่ชอบที่จะต้องทำงานกับบริการที่มีระเบียบเล็กน้อย แม้ว่าฉันจะไม่เห็นเหตุผลใด ๆ ที่คุณไม่สามารถใช้รูปแบบเดียวกันในการแยกไมโครเซอร์วิสและการรวมเป็นส่วนหน้าที่ใช้งานได้มากขึ้นสำหรับลูกค้าของคุณดังนั้นไมโครเซอร์วิสสามารถเปลี่ยนแปลงได้โดยไม่ส่งผลกระทบต่อส่วนหน้า
Luke Puplett

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