ตกลงเปลี่ยนบางส่วนของคอลเลกชันด้วย PUT หรือ DELETE หรือไม่?


21

ฉันมีชุดผลิตภัณฑ์ในกลุ่มผลิตภัณฑ์เช่น:

product-groups/123/products
  1. ถ้าฉันต้องการเพิ่มลงในคอลเลกชันฉันจะส่งผลิตภัณฑ์บางอย่างที่มี PUT ได้หรือไม่

  2. หากฉันต้องการลบผลิตภัณฑ์บางอย่างออกจากคอลเลกชันฉันจะส่งข้อมูลตัวกรอง (อาร์เรย์ของ ID) ด้วย DELETE ได้หรือไม่

เป็นวิธีที่ดีที่สุดในการใช้งานฟังก์ชันในจิตวิญญาณของ ReST อะไร

แก้ไข: รายการเหล่านี้เป็นลิงค์ไปยังเอนทิตีที่แยกจากกันโดยทั่วไปเป็น ID ของผลิตภัณฑ์


รายการในกลุ่มผลิตภัณฑ์มีการจัดการทรัพยากรแยกต่างหากที่อื่นหรือไม่ หรือพวกเขาเป็นเพียงส่วนหนึ่งของการรวบรวมกลุ่มผลิตภัณฑ์? หากแยกกันผลิตภัณฑ์จะอยู่ในกลุ่มผลิตภัณฑ์หลายกลุ่มได้หรือไม่
Martijn Pieters

2
บางทีPATCH ข้อมูลจำเพาะนี้จะกำหนดวิธีการ HTTP / 1.1 [RFC2616] ใหม่คือ PATCH ซึ่งใช้ในการปรับใช้บางส่วนกับทรัพยากร
Esailija

ผลิตภัณฑ์ (ID) สามารถอยู่ในกลุ่มผลิตภัณฑ์หลายกลุ่ม
user151851

มีวิธีที่รู้จักกันดี (วิธีปฏิบัติที่ดีที่สุด) ที่จะพูดถึงวิธีการแพทช์คือการเพิ่มหรือลบผลิตภัณฑ์ในคอลเลกชัน?
user151851

คำถามที่คล้ายกันเกี่ยวกับ SO stackoverflow.com/questions/411462/…
Luke Puplett

คำตอบ:


10

โดยทั่วไปคุณมีจุดปลายเดียวซึ่งแสดงถึงชุดทั้งหมดของx :

/products

บอกว่าคุณต้องการที่จะปรับปรุงผลิตภัณฑ์เดียวที่คุณจะPUT/products/{id}ไป หากคุณต้องการที่จะปรับปรุงผลิตภัณฑ์เดียว (ไม่ได้อัปเดตทุกสาขา) บางส่วนนอกจากนี้คุณยังสามารถใช้PATCH/products/{id}ไป การลบเอนทิตีเดียว ( DELETEถึง/products/{id})

หากคุณต้องการกำหนดเป้าหมายแหล่งทรัพยากรเดียวคุณต้องผ่านเส้นทางซึ่งแหล่งทรัพยากรเดียวคุณต้องการแก้ไข

การดำเนินการเพียงอย่างเดียวที่ทำให้แผนการแตกคือการสร้างแหล่งข้อมูล เมื่อมีการสร้าง Ressource ที่คุณกำหนดเป้าหมายการเก็บรวบรวมเป็นทั้งบอกว่าโพสต์/productsไป

ที่กล่าวไว้ชัดเจนว่าเป้าหมายสำหรับการดำเนินงานที่มีผลต่อการรวบรวมโดยรวมควรไปที่จุดรวบรวมปลายทางที่เหมาะสม

เช่นคุณต้องการเรียกคืนชุดย่อยของผลิตภัณฑ์ที่เป็นสีแดง

ได้รับ/products?colour=redการ

ดังนั้นถ้าคุณต้องการที่จะลบทั้งหมดเหล่านี้คุณลบ /products?colour=redหรือถ้าคุณต้องการที่จะลบผลิตภัณฑ์บางอย่างผ่านidคุณสามารถลบ /products?id=1&id=2&id=3ได้

สิ่งที่เกี่ยวกับการสร้างทรัพยากรจำนวนมาก ? โพสต์คอลเลกชันของคุณเพียงเพื่อ[{...},{...},{...}] /productsเดียวกันจะไปสำหรับPUTและPATCH

นั่นตรงไปตรงมาจริงๆ

ในการตอบคำถามของคุณ:

ถ้าฉันต้องการเพิ่มลงในคอลเลกชันฉันจะส่งผลิตภัณฑ์บางอย่างที่มี PUT ได้หรือไม่

ไม่เพียง แต่คุณจะได้รับการสนับสนุนให้ทำเช่นนั้น

หากฉันต้องการลบผลิตภัณฑ์บางอย่างออกจากคอลเลกชันฉันจะส่งข้อมูลตัวกรอง (อาร์เรย์ของ ID) ด้วย DELETE ได้หรือไม่

ไม่เป็นไร ในฐานะที่เป็นอลอนโซ่ Eneko เขียนบางครั้งมีbulkoperationsห่อหุ้มผ่าน "ควบคุม" -endpoints ด้วยอาทิPOSTจะใช้ในการดำเนินงานของทริกเกอร์ (ที่ซับซ้อน)


2
PUT เป็นการดำเนินการแทนที่ การเรียก PUT บนจุดปลายทางการรวบรวมด้วย "ผลิตภัณฑ์บางอย่าง" ควรลบ (ในกรณีของ OP ลบความสัมพันธ์) ผลิตภัณฑ์ใด ๆ ที่ไม่รวมอยู่ในรายการ "ผลิตภัณฑ์บางอย่าง" ในขณะที่มันสามารถใช้ในการเพิ่มรายการ แต่ก็ควรลบรายการที่ไม่ได้ (ในความคิดของฉัน) สิ่งที่ OP คาดหวัง คุณควรทบทวนคำตอบของคำถามแรก
claytond

@claytond: ฉันคิดว่าคำตอบคือดีตราบใดที่มีการปรับปรุงบางส่วนจะทำกับและทดแทนที่สมบูรณ์ผ่านทางPATCH PUT
9000

4
@ 9000 แน่นอน แต่คำตอบในปัจจุบันกล่าวว่า "คุณได้รับการสนับสนุนให้ ... เพิ่มในคอลเลกชัน ... [โดย] ส่ง [อิง] เฉพาะบางผลิตภัณฑ์ที่มี PUT" นั่นไม่ถูกต้องอย่างแน่นอน สนับสนุนให้ POST สามารถวาง ... แต่เพียงผ่านรายการทั้งหมด (ไม่ใช่บางรายการ)
claytond

5

โดยปกติแล้วเมธอด REST จะตั้งใจให้ทำงานกับเอนทิตี / วัตถุเดียว (CRUD)

มีหลายตัวเลือก:

  • ปฏิบัติต่อคอลเลกชันของคุณเป็นเอนทิตีและอัปเดตผ่านทาง POST
  • สร้างการดำเนินการสำรองไม่ใช่แบบ REST

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

ตัวเลือกที่สองเป็นที่ต้องการของ API จำนวนมากซึ่งเป็นวิธีการขยาย REST เกินกว่าการดำเนินการ CRUD

ตัวอย่างเช่น:

GET product-groups/123/products (list all the products in the group)
POST product-groups/123/products/append (POST a list of new product ids to append to the group)
POST product-groups/123/products/remove (POST a list of product ids to remove from the group)

APIs จำนวนมากใช้ POST เสมอสำหรับการดำเนินการที่ขยายนี้ แต่ไม่มีสิ่งใด จำกัด ให้คุณใช้วิธีการ http อื่น ๆ (นอกเหนือจาก limitatio ของ GET และ DELETE เพื่อให้มีเนื้อความว่างเปล่า)


แน่นอนว่ามีสองสามวิธีในการบรรลุเป้าหมาย ข้อใดเป็นแนวทางปฏิบัติที่ดีที่สุด อันไหนจะเป็นหลักฐานในอนาคตมากขึ้น?
user151851

4
@ user151851: การปฏิบัติตาม REST ทั้งหมด (หากมีสิ่งนั้น) เป็นเป้าหมายที่สูงส่ง โครงร่างแนวทางที่นี่ดูเหมือนจริงมากขึ้นดังนั้นในขณะที่พยายามใช้วิธีการที่ใช้จริงใน "โลกแห่งความเป็นจริง" ทำให้เป็นสาระสำคัญมาตรฐาน defacto นั่นเป็นหลักฐานเกี่ยวกับอนาคตที่คุณจะได้รับ
Robert Harvey

2
เราไม่แนะนำคำกริยาที่กำหนดเองโดยใช้ "ผนวก" และ "ลบ" ใน URL ใช่ไหม ด้วยวิธีนี้เราจะต้องอธิบายวิธีการใช้ API เราไม่ควรใช้สิ่งที่เรามีเช่นวิธี HTTP อีกครั้ง ในกรณีนี้การกระทำที่เป็นที่รู้จักกันดี
user151851

7
สำหรับคนอื่นที่เกิดขึ้นกับคำตอบนี้มันผิด ดังที่ @ user151851 ได้กล่าวถึงสิ่งนี้จะนำคำกริยามาใช้ใน URL ซึ่งไม่เกี่ยวกับคำว่า RESTful เท่าที่คุณจะได้รับ ในเรื่องที่เกี่ยวกับคำถามที่เกิดขึ้นจริงฉันไม่มีคำตอบที่ดี แต่นี่ไม่ใช่คำถาม
umbrae

"ส่วนขยาย" สามารถใช้ทรัพยากรได้มากกว่าโดยการทำให้ส่วนproducts/collectionที่ส่งคืน 'ซองจดหมาย' ของรายการและเนื้อหาซองจดหมายเปลี่ยนผ่าน PUT หรือไม่ กดไลค์ "นี่คือวิธีที่ฉันต้องการให้ไอเท็มในคอลเล็กชันเป็น"
ลุค Puplett

3

เพียงเพื่อตอบ / แสดงความคิดเห็นก่อนหน้าอย่างแม่นยำ

ตามความรู้ของฉัน POST เป็นวิธีการเพิ่มองค์ประกอบเดียวไปยังคอลเลกชัน

ในทางกลับกัน DELETE เป็นวิธีการลบองค์ประกอบเดียวจากคอลเลกชัน สถานการณ์ทั้งสองนั้นสงบอย่างสมบูรณ์แบบ

อย่างไรก็ตามคุณควรใช้ URI ที่เหมาะสมเพื่ออ้างอิงองค์ประกอบเดียวหรือชุดรวมทั้งหมด

ตัวอย่างเช่นหากต้องการเพิ่มองค์ประกอบในการรวบรวมคุณควรโพสต์ข้อมูลลงใน URI ต่อไปนี้:

https://www.factory.net/products/

หากต้องการลบผลิตภัณฑ์เดียวออกจากคอลเล็กชันคุณสามารถใช้วิธี DELETE เพื่อส่งคำขอไปยังสิ่งต่อไปนี้:

https://www.factory.net/products/108/

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


2

โดยหลักการแล้วการดำเนินการ RESTful ทั้งหมดนั้นใช้ได้กับคอลเล็กชั่น แต่ต้องแน่ใจว่าคุณเข้าใจว่าซีแมนติกส์ของคำกริยาใช้กับคอลเลกชันอย่างไร:

  • PUT เป็นการทดแทนที่สมบูรณ์

    • หากคุณใส่ลงไปในซิงเกิล (เช่น/item/{id}) และออกnameไปก็ควรจะล้างหรือตั้งค่าเป็นโมฆะหรือสิ่งที่คล้ายกัน
    • หากคุณใส่ในคอลเล็กชันและไม่รวมไอเท็มควรลบออกจากคอลเล็กชันนั้น

    ในขณะที่ PUT สามารถใช้เพื่อเพิ่มรายการคุณต้องส่งรายการ "ทั้งหมด" การส่งรายการ "บางอย่าง" ควรส่งผลให้มีการลบ (ฉันถือว่านี่ไม่ใช่สิ่งที่ OP ต้องการ)

  • DELETE ใช้งานง่ายขึ้น การลบคอลเลกชันหรือชุดย่อยใด ๆ ที่ถูกกรองนั้นถูกต้อง เฉพาะรายการที่รวมอยู่ในตัวกรองเท่านั้นที่ควรได้รับผลกระทบ

  • PATCH ก็ใช้ได้เช่นกัน ในทางทฤษฎีคุณควรจะให้รายการ "การดำเนินการ" ตัวอย่างเช่นคุณควรส่งตัวอย่างเช่นเทคนิค:

    [{ 
        "action": "update",
        "id": <id>,
        "value": {...}
    },{
        "action": "add",
        "value": {...}
    }, ...]
    

    ในทางปฏิบัติมันเป็นเรื่องธรรมดามากที่จะเห็น API ที่ยอมรับรายการบางส่วนของวัตถุที่ประมวลผลแต่ละรายการโดยใช้ตรรกะ UPSERT (อัปเดตหรือแทรก)

  • ในทางเทคนิค POST ควรประมวลผลอินพุต "ตามความหมายเฉพาะของทรัพยากร"

    • ในทางปฏิบัติ POST มักใช้สำหรับการดำเนินการ "สร้าง"
    • อย่างไรก็ตาม POST ยังเป็นคำกริยาที่ใช้สำหรับการโทรที่ไม่ได้มาตรฐาน ในขณะที่มีการถกเถียงกันอย่างจริงจังว่าจุดสิ้นสุดการกระทำนั้นสงบนิ่งหรือไม่ (ฉันเข้าข้าง "ไม่") POST เป็นคำกริยาที่เหมาะสมหากคุณส่งคำขอไปยังจุดปลายเช่น{resource}/activateนั้น

หมายเหตุ: เมื่อใช้การดำเนินการที่ไม่ใช่ GET กับคอลเลกชันให้พิจารณาคำจำกัดความของความสำเร็จและความล้มเหลวอย่างรอบคอบ REST ไม่ได้ให้วิธีที่ดีในการสื่อสารความสำเร็จบางส่วน เริ่มต้นที่ดีคือการสมมติว่าคุณจะเรียกใช้การดำเนินการในการทำธุรกรรมที่มีเกณฑ์ความสำเร็จทั้งหมดหรือไม่มีอะไร หากนี่ไม่ใช่สิ่งที่คุณต้องการคุณอาจไม่ควรโต้ตอบกับคอลเล็กชันโดยตรง

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