วิธีที่น่าสนใจในการสร้างหลายรายการในคำขอเดียว


122

ฉันกำลังทำงานกับโปรแกรมเซิร์ฟเวอร์ไคลเอนต์ขนาดเล็กเพื่อรวบรวมคำสั่งซื้อ ฉันต้องการทำสิ่งนี้ด้วยวิธี "REST (ful)"

สิ่งที่ฉันต้องการทำคือ:

รวบรวมรายการสั่งซื้อทั้งหมด (ผลิตภัณฑ์และปริมาณ) และส่งคำสั่งซื้อทั้งหมดไปยังเซิร์ฟเวอร์

ในขณะนี้ฉันเห็นสองตัวเลือกในการดำเนินการนี้:

  1. ส่งแต่ละ orderline ไปยังเซิร์ฟเวอร์: POST qty และ product_id

ที่จริงฉันไม่ต้องการทำเช่นนี้เพราะฉันต้องการ จำกัด จำนวนคำขอไปยังเซิร์ฟเวอร์ดังนั้นตัวเลือกที่ 2:

  1. รวบรวมรายการสั่งซื้อทั้งหมดและส่งไปยังเซิร์ฟเวอร์พร้อมกัน

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

เป็นความคิดที่ดีหรือแนวทางปฏิบัติที่ดีในการนำตัวเลือกที่ 2 ไปใช้และถ้าเป็นเช่นนั้นฉันควรทำอย่างไร

การปฏิบัติที่ดีคืออะไร?

rest  post 

คำตอบ:


74

ฉันเชื่อว่าอีกวิธีหนึ่งที่ถูกต้องในการเข้าถึงสิ่งนี้คือการสร้างทรัพยากรอื่นที่แสดงถึงการรวบรวมทรัพยากรของคุณ ตัวอย่างสมมติว่าเรามีจุดสิ้นสุดเหมือน/api/sheep/{id}และเราสามารถ POST /api/sheepเพื่อสร้างทรัพยากรแกะ

ตอนนี้หากเราต้องการสนับสนุนการสร้างจำนวนมากเราควรพิจารณาแหล่งข้อมูลฝูงใหม่ที่/api/flock(หรือ/api/<your-resource>-collectionหากคุณไม่มีชื่อที่มีความหมายดีกว่านี้) โปรดจำไว้ว่าทรัพยากรไม่จำเป็นต้องแมปกับฐานข้อมูลหรือโมเดลแอปของคุณ นี่เป็นความเข้าใจผิดที่พบบ่อย

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

ฉันคิดว่ามันปลอดภัยที่จะสมมติว่าการใช้ทรัพยากรอาจหมายถึงการสร้างเอนทิตีอื่น ๆ ขึ้นมาเพื่อเป็นผลข้างเคียง


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

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

2
ฉันชอบคุณ api endpoint ที่ตั้งชื่อแกะและฝูงแกะมาก! ด้วยระดับความเป็นนามธรรมมันเกือบจะมีการอ้างอิงตามพระคัมภีร์ไบเบิล: "ฉันมีแกะตัวอื่นซึ่งไม่ใช่ของคอกนี้ฉันต้องนำพวกมันมาด้วยและพวกเขาจะได้ยินเสียงของเราและพวกเขาจะกลายเป็นฝูงเดียวกับผู้เลี้ยงคนเดียว" ยอห์น 10:16.
Evgeny

1
ที่น่าสนใจคือผู้คนแนะนำให้ใช้รูปพหูพจน์ (ของคอลเล็กชัน) ใน URL เมื่อคุณต้องการสร้างทรัพยากรเดียวเช่นส่ง POST ไปที่ / api / books เพื่อสร้างหนังสือ แต่เมื่อคุณต้องการสร้างหนังสือ 100 เล่ม (ในคำขอเดียวเป็น json) คุณจะโพสต์ชุดหนังสือ 100 เล่มไปที่ URL ใด นั่นคือจุดเริ่มต้นของความร้อนรน
code4kix

@ code4kix คุณสามารถใช้/api/book-group, /api/book-collectionหรือสิ่งที่คล้ายกัน
miguelcobain

46

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

ฉันพบว่าการโพสต์คอลเลคชันตามที่คุณแนะนำโดยทั่วไปใช้งานได้จริง แต่ปัญหาจะเกิดขึ้นเมื่อคุณต้องรายงานความล้มเหลวตามคำขอดังกล่าว ปัญหาดังกล่าวแย่ลงเมื่อเกิดความล้มเหลวหลายครั้งด้วยสาเหตุที่แตกต่างกันหรือเมื่อเซิร์ฟเวอร์ไม่รองรับธุรกรรม ข้อเสนอแนะของฉันสำหรับคุณคือหากไม่มีปัญหาด้านประสิทธิภาพตัวอย่างเช่นเมื่อผู้ให้บริการอยู่บน LAN (ไม่ใช่ WAN) หรือข้อมูลมีขนาดค่อนข้างเล็กควรส่งคำขอ POST 100 รายการไปยังเซิร์ฟเวอร์ ทำให้ง่ายเริ่มต้นด้วยคำขอแยกต่างหากและหากคุณมีปัญหาด้านประสิทธิภาพให้พยายามปรับให้เหมาะสม


3
คุณพบวิธีแก้ปัญหาด้วยตัวเองสำหรับข้อผิดพลาดในกรณีของแบทช์หรือไม่? ในการเชื่อมต่อมือถือส่งคำขอโพสต์ 100 รายการเพื่อแสดงตะเข็บหน้าเหมือนเป็นความคิดที่ไม่ดี
Thomas Ahle

ฉันผนวกข้อผิดพลาดเข้ากับอาร์เรย์กำหนดเส้นทางผู้ใช้ไปยังหน้าข้อผิดพลาด 419 Conflict (และส่งคืนข้อผิดพลาดนั้นไปยังไคลเอนต์) และแสดงอาร์เรย์ของข้อผิดพลาด ดูคำตอบของฉันด้านล่างสำหรับรายละเอียดเพิ่มเติม
Eric Fuller

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

2
@thecoshman มีการเปลี่ยนแปลงมากมายในรอบ 3.25 ปี คุณควรโพสต์คำตอบที่กำหนดไว้อย่างสมบูรณ์สำหรับคำถาม
dlamblin

3
@dlamblin ใช่ฉันน่าจะทำหลายอย่าง ... ฉันจะไปถึงมันในบางช่วงบางที ...
thecoshman

9

Facebook อธิบายวิธีการทำสิ่งนี้: https://developers.facebook.com/docs/graph-api/making-multiple-requests

คำขอเป็นกลุ่มง่ายๆ

batch API ใช้อาร์เรย์ของคำขอ HTTP เชิงตรรกะที่แสดงเป็นอาร์เรย์ JSON แต่ละคำขอมีวิธีการ (สอดคล้องกับวิธี HTTP GET / PUT / POST / DELETE ฯลฯ ), relative_url (ส่วนของ URL หลัง graph.facebook com), อาร์เรย์ส่วนหัวที่เป็นทางเลือก (สอดคล้องกับส่วนหัว HTTP) และเนื้อหาเสริม (สำหรับคำขอ POST และ PUT) Batch API ส่งคืนอาร์เรย์ของการตอบสนอง HTTP แบบลอจิคัลที่แสดงเป็นอาร์เรย์ JSON - การตอบสนองแต่ละรายการมีรหัสสถานะอาร์เรย์ส่วนหัวที่เป็นทางเลือกและเนื้อความทางเลือก (ซึ่งเป็นสตริงที่เข้ารหัส JSON)


1
นี่เป็นลิงค์ที่น่าสนใจมากโซลูชันที่เสนอดูเหมือนจะใช้งานได้สำหรับฉัน อย่างไรก็ตามที่คำตอบที่ต้องการของ StackOverflow คือการอธิบายแนวคิดของโซลูชันในเนื้อหาของคำตอบเนื่องจากลิงก์อาจเปลี่ยนแปลงหรือหายไป
ม.ค. Vlcinsky

7
นั่นเป็นวิธีการของ Facebook จริงๆไม่จำเป็นต้อง RESTful ตามที่ OP ถาม
0cd

ฉันคิดว่า Batch API (จาก Google, Facebook และอื่น ๆ - @PuneetArora) มีประโยชน์มากกว่าเมื่อจัดกลุ่มคำขอที่ไม่เกี่ยวข้องหลายรายการเข้าด้วยกัน การสร้างคำขอที่สร้างรายการหนึ่งรายการจากนั้นจัดกลุ่มคำขอทั้งหมดเข้าด้วยกันเพื่อส่งคอลเล็กชันรายการคือ "ความวิกลจริต" (Einstein) เพียงแค่สร้างคำขอที่ส่งผ่านคอลเลกชันของรายการ
tfmontague

8

ความคิดของคุณถูกต้องสำหรับฉัน การนำไปใช้เป็นเรื่องของความชอบของคุณ คุณสามารถใช้ JSON หรือเพียงแค่พารามิเตอร์สำหรับอาร์เรย์นี้ ("order_lines []") และทำ

POST /orders

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


6

ผมคิดว่ามันจะดีกว่าที่จะส่งคำขอแยกต่างหากภายในเชื่อมต่อเดียว แน่นอนว่าเว็บเซิร์ฟเวอร์ของคุณควรรองรับ


5

เมื่อเร็ว ๆ นี้ฉันได้ต่อสู้กับเรื่องนี้มาแล้วและนี่คือสิ่งที่ฉันกำลังทำอยู่

หากการโพสต์ที่เพิ่มทรัพยากรหลายรายการสำเร็จให้ส่งคืน 200 OK (ฉันกำลังพิจารณา 201 แต่ในที่สุดผู้ใช้จะไม่เข้าสู่ทรัพยากรที่สร้างขึ้น) พร้อมกับเพจที่แสดงทรัพยากรทั้งหมดที่เพิ่มไม่ว่าจะเป็นแบบอ่าน - แฟชั่นเท่านั้นหรือแก้ไขได้ ตัวอย่างเช่นผู้ใช้สามารถเลือกและโพสต์ภาพหลายภาพไปยังแกลเลอรีโดยใช้แบบฟอร์มที่ประกอบด้วยอินพุตไฟล์เดียวเท่านั้น หากคำขอ POST ประสบความสำเร็จอย่างสมบูรณ์ผู้ใช้จะได้รับชุดฟอร์มสำหรับการแสดงทรัพยากรรูปภาพแต่ละรายการที่สร้างขึ้นซึ่งอนุญาตให้ระบุรายละเอียดเพิ่มเติมเกี่ยวกับแต่ละรายการ (ชื่อคำอธิบาย ฯลฯ )

ในกรณีที่ไม่สามารถสร้างทรัพยากรอย่างน้อยหนึ่งทรัพยากรตัวจัดการ POST จะยกเลิกการประมวลผลทั้งหมดและผนวกข้อความแสดงข้อผิดพลาดแต่ละรายการเข้ากับอาร์เรย์ จากนั้นข้อขัดแย้ง 419 จะถูกส่งกลับและผู้ใช้จะถูกส่งไปยังเพจข้อผิดพลาด 419 Conflict ที่แสดงเนื้อหาของอาร์เรย์ข้อผิดพลาดตลอดจนวิธีกลับไปยังแบบฟอร์มที่ถูกส่ง


-2

คุณไม่ต้องการส่งส่วนหัว HTTP สำหรับ 100 orderlines คุณไม่ต้องการสร้างคำขอใด ๆ มากเกินความจำเป็น

ส่งคำสั่งทั้งหมดในออบเจ็กต์ JSON ไปยังเซิร์ฟเวอร์ไปที่: เซิร์ฟเวอร์ / คำสั่งหรือเซิร์ฟเวอร์ / คำสั่ง / ใหม่ ส่งคืนสิ่งที่ชี้ไปที่: เซิร์ฟเวอร์ / order / order_id

ลองพิจารณาใช้CREATE PUT แทน POST


ฉันคิดว่าเขาพูดถึงวิธี HTTP POST ไม่มีสิ่งที่เรียกว่า CREATE HTTP method
Milan Novota

ไม่มีเหรอ? โอ้เดี๋ยวก่อนไม่มี มี PUT แทน
Cheery

22
ทำไมคุณถึงใช้ PUT ในการสร้างเนื้อหา นี่คือสิ่งที่เมธอด HTTP POST มีไว้สำหรับ
thecoshman

8
คุณใช้ PUT เพื่อสร้างทรัพยากรเมื่อคุณต้องการให้ไคลเอนต์ระบุ URI ของทรัพยากรเช่นใน webdav ฉันไม่เห็นด้วยกับการใช้ PUT ของผู้โพสต์ แต่มีสถานที่ในการสร้างทรัพยากรแม้ว่าสถานที่นั้นอาจมีขอบเขต จำกัด
user602525

2
หมายเหตุ: การโพสต์เอนทิตีควรส่งผลให้เอนทิตีกลายเป็นผู้อยู่ใต้บังคับบัญชาของทรัพยากรที่ระบุในคำขอและไม่ใช่สิ่งที่มีอยู่ PUT แทนที่เอนทิตีตามที่อยู่และเป็น idempotent idempotency (word?) คือความคาดหวังที่สำคัญสำหรับผู้บริโภค
Luke Puplett
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.