รูปแบบที่ดีที่สุดสำหรับการเพิ่มไอเท็มที่มีอยู่ในคอลเล็กชันใน REST API คืออะไร


23

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

API ของฉันจะช่วยให้ผู้บริโภคสามารถเพิ่มเว็บไซต์ที่มีอยู่ในโครงการ ที่ที่ฉันต้องวางสายคือข้อมูลเดียวที่ฉันต้องการจริงๆคือ ProjectId และ SiteId แนวคิดเริ่มต้นของฉันคือ:

1. POST myapi/projects/{projectId}/sites/{siteId}

แต่ฉันก็คิดถึง

2. POST myapi/projects/{projectId}/sites

ด้วยเอนทิตีของไซต์ที่ส่งเป็นเนื้อหา JSON

ตัวเลือกที่ 1 นั้นง่ายและใช้งานได้ แต่รู้สึกไม่ถูกต้องและฉันมีความสัมพันธ์อื่น ๆ ที่ไม่สามารถทำตามรูปแบบนี้ดังนั้นมันจึงเพิ่มความไม่สอดคล้องกับ API ของฉัน

ตัวเลือก 2 รู้สึกดีขึ้น แต่นำไปสู่ข้อกังวลสองข้อ:

  • ฉันควรสร้างเว็บไซต์หรือส่งข้อยกเว้นหากมีการโพสต์ไซต์ใหม่ (SiteId = 0)
  • เนื่องจากฉันต้องการเพียง ProjectId และ SiteId เพื่อสร้างความสัมพันธ์ไซต์อาจถูกโพสต์ด้วยข้อมูลที่ผิดหรือขาดหายไปสำหรับคุณสมบัติอื่น ๆ

ตัวเลือกที่ 3 คือการจัดเตรียมจุดปลายอย่างง่ายเพียงอย่างเดียวสำหรับการสร้างและลบความสัมพันธ์ จุดสิ้นสุดนี้คาดว่าจะมี JSON ส่วนของข้อมูลที่บรรจุเพียง ProjectId และ SiteId

คุณคิดอย่างไร?


2
ดูเพิ่มเติมได้ที่: stackoverflow.com/questions/2001773/…
Rory Hunter

@RoryHunter มีการสนทนาที่น่าสนใจในลิงค์นี้ แต่ไม่มีอะไรที่กำจัดความไม่แน่นอนของฉันได้ ฉันชอบโดยเฉพาะอย่างยิ่งคำตอบที่ได้รับการยอมรับระบุว่า "คุณเข้าใจถูกต้อง" และสถานที่ที่ 2 (แม้ว่าจะเป็นขอบขนาดใหญ่) คำตอบ "เพียงแค่คุณทำสิ่งนี้ย้อนหลังอย่างสมบูรณ์"
Jamie Ide

ตัวเลือกแรกของคุณใช้ได้แม้ว่าฉันจะใช้ PUT แทน POST เนื่องจากไคลเอนต์อยู่ในการควบคุมตัวตนที่ถูกเพิ่มเข้าไปในคอลเลกชัน ข้อกังวลแรกของคุณที่มีตัวเลือกที่ 2 นั้นขึ้นอยู่กับคุณทั้งหมดหากคุณไม่ต้องการไซต์ใหม่อย่าโยนข้อยกเว้น แต่ส่งคืนรหัส 4xx ข้อใดข้อหนึ่ง ข้อกังวลประการที่สองของคุณไม่ได้อยู่ที่นี่หรือที่นั่น คุณไม่ควรโพสต์ทั้งไซต์เว้นแต่คุณจะอนุญาตการเพิ่มเติม การเพิ่มไซต์ที่มีอยู่ควรมีรหัสเฉพาะเมื่อคุณกำลังปรับเปลี่ยนไซต์ แต่เฉพาะคอลเลกชัน "ProjectSite" (แม้ว่าคุณจะไม่ได้สร้างทรัพยากรแยกต่างหาก)
Marjan Venema

คำตอบ:


14

POST คือกริยา "ผนวก" และกริยา "การประมวลผล" PUT เป็นคำกริยา "สร้าง / อัปเดต" (สำหรับตัวระบุที่รู้จัก) และเกือบจะดูเหมือนตัวเลือกที่ถูกต้องที่นี่เพราะเป็นที่รู้จักกันใน URI เป้าหมายทั้งหมด projectIdและsiteIdมีอยู่แล้วดังนั้นคุณไม่จำเป็นต้อง "โพสต์ไปยังคอลเลกชัน" เพื่อสร้าง ID ใหม่

ปัญหาของ PUT คือมันต้องการให้ร่างกายเป็นตัวแทนของทรัพยากรที่คุณกำลังวาง แต่เจตนาที่นี่คือการผนวกเข้ากับทรัพยากรการเก็บรวบรวม "โครงการ / เว็บไซต์" มากกว่าการปรับปรุงทรัพยากรเว็บไซต์

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

ข้อมูลเดียวที่ฉันต้องการจริงๆคือ ProjectId และ SiteId

แต่ฉันจะลองโพสต์siteIdไปยังคอลเล็กชันและพึ่งพาธรรมชาติ "ผนวก" และ "กระบวนการ" ของ POST:

POST myapi / projects / {projectId} / sites

{'id': '... '}

เนื่องจากคุณกำลังแก้ไขทรัพยากรการรวบรวมไซต์และไม่ใช่ทรัพยากรของไซต์นั่นคือ URI ที่คุณต้องการ POST สามารถรู้ว่า "ผนวก / ประมวลผล" และเพิ่มองค์ประกอบที่มี id นั้นในไซต์คอลเลกชันของโครงการ

ที่ยังคงเปิดประตูต่อการสร้างไซต์ใหม่สำหรับโครงการโดยใช้ JSON และละเว้น ID "ไม่มี id" == "สร้างตั้งแต่เริ่มต้น" แต่ถ้าคอลเลกชัน URI ได้รับ ID และไม่มีอะไรอื่นมันค่อนข้างชัดเจนว่าจะต้องเกิดอะไรขึ้น

คำถามที่น่าสนใจ :)


ฉันมีความเชื่อที่เชื่อว่า POST นั้นมีไว้สำหรับการสร้างและ PUT นั้นมีไว้สำหรับการอัปเดต แต่ข้อสรุปของคุณคือที่ที่ฉันสิ้นสุดเมื่อวานนี้ สิ่งที่ดีคือต้องขอบคุณแอตทริบิวต์การกำหนดเส้นทางใน Web API ฉันมีรหัสในตัวควบคุม ProjectSites เพื่อให้มีการจัดระเบียบรหัสอย่างดี
Jamie Ide

ฉันคิดว่าเหตุผลการกำหนดที่คุณต้องการใช้POSTแทนPUTหรือPATCHที่นี่คือคุณไม่มีSiteเอนทิตีทั้งหมดที่จะใส่ลงในsitesทรัพยากร คุณมี ID ซึ่งต้องการการประมวลผลเพื่อเพิ่มลงในคอลเลกชัน
บดขยี้

4

เราใช้Patchวิธีสำหรับสิ่งเช่นนี้ สิ่งที่คุณต้องการทำคือปรับเปลี่ยนโครงการที่มีอยู่เพื่อเพิ่มไซต์เข้าไป

ดังนั้นสิ่งนี้จะได้ผล

PATCH myapi/projects/{id} 

กับเอนทิตีของไซต์เป็น JSON / JSONArray ในเนื้อความของคำขอ

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


แนวทางที่น่าสนใจ ฉันมีรูปแบบโดเมนเก่าที่ "รวย" (ขึ้นอยู่กับสูง) และโครงการโดยเฉพาะมีคอลเลกชันจำนวนมากที่แขวนไว้ การตรวจสอบประเภทเอนทิตีที่อยู่ในคำร้องขอนั้นเป็นสิ่งที่ท้าทายและไม่สอดคล้องกับเป้าหมายในทางปฏิบัติของฉัน
Jamie Ide

ทำไมจึงเป็นเรื่องท้าทาย หากคุณมีข้อ จำกัด เหล่านี้คุณสามารถใช้ JSON เพื่อระบุสิ่งที่กำลังส่ง ... เช่น{"sites": [], "other-stuff": {}}คุณสามารถแยกรหัสเพื่อจัดการ "subjsons" ทั้งหมดได้อย่างง่ายดาย มันขึ้นอยู่กับปัญหาเฉพาะของคุณ แต่ฉันขอแนะนำให้ใช้ PATCH เพราะมันออกแบบมาสำหรับสิ่งเหล่านี้โดยเฉพาะ
juan

ข้อเสียที่ฉันเห็นคือ 1) API ไม่สื่อสารอย่างชัดเจนว่าคอลเล็กชันใดที่อนุญาตให้เปลี่ยนแปลง 2) ไม่สามารถใช้ประโยชน์จากการเชื่อมพารามิเตอร์ Web API ได้; 3) สวิตช์ใหญ่หรือถ้ามีคำสั่ง
Jamie Ide

ฉันไม่เคยเห็นวิธีการแพทช์ใช้ที่อื่นเลย
NimChimpsky

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