อะไรคือแนวปฏิบัติที่ดีที่สุดสำหรับทรัพยากรที่ซ้อนกัน REST


301

เท่าที่ฉันสามารถบอกได้ว่าทรัพยากรแต่ละรายการควรมีเพียงเส้นทางเดียวเท่านั้น ดังนั้นในตัวอย่างต่อไปนี้รูปแบบ URL ที่ดีจะเป็นอย่างไร

ยกตัวอย่างการเป็นตัวแทน บริษัท ที่เหลือ ในตัวอย่างสมมุตินี้แต่ละ บริษัทเป็นเจ้าของ 0 หรือมากกว่าแผนกและแต่ละแผนกเป็นเจ้าของ 0 หรือมากกว่าพนักงาน

แผนกไม่สามารถอยู่ได้หากไม่มี บริษัท ที่เกี่ยวข้อง

พนักงานไม่สามารถอยู่ได้หากไม่มีแผนกที่เกี่ยวข้อง

ทีนี้ฉันก็พบว่ารูปแบบของทรัพยากรนั้นเป็นตัวแทนของธรรมชาติ

  • /companies ชุดของ บริษัท - ยอมรับการจัดตั้ง บริษัท ใหม่ รับทั้งชุด
  • /companies/{companyId}บริษัท เอกชน ยอมรับ GET, PUT และ DELETE
  • /companies/{companyId}/departmentsยอมรับ POST สำหรับรายการใหม่ (สร้างแผนกภายใน บริษัท )
  • /companies/{companyId}/departments/{departmentId}/
  • /companies/{companyId}/departments/{departmentId}/employees
  • /companies/{companyId}/departments/{departmentId}/employees/{empId}

ด้วยข้อ จำกัด ในแต่ละส่วนฉันรู้สึกว่ามันสมเหตุสมผลถ้าซ้อนกันลึกลงไปเล็กน้อย

อย่างไรก็ตามความยากลำบากของฉันเกิดขึ้นถ้าฉันต้องการแสดงรายการ ( GET) พนักงานทุกคนในทุก บริษัท

รูปแบบทรัพยากรสำหรับแผนที่นั้นใกล้เคียงที่สุด/employees(การรวบรวมพนักงานทั้งหมด)

นั่นหมายความว่าฉันควรจะมี/employees/{empId}เพราะถ้าเป็นเช่นนั้นมีสอง URI ของการได้รับทรัพยากรเดียวกันได้หรือไม่

หรืออาจเป็นแบบแผนทั้งหมดควรจะแบน แต่นั่นหมายความว่าพนักงานเป็นวัตถุระดับบนสุดที่ซ้อนกัน

ในระดับพื้นฐาน/employees/?company={companyId}&department={deptId}จะให้มุมมองที่เหมือนกันกับพนักงานในรูปแบบซ้อนกันมากที่สุด

แนวปฏิบัติที่ดีที่สุดสำหรับรูปแบบ URL ที่เป็นเจ้าของทรัพยากรโดยทรัพยากรอื่น ๆ คืออะไร แต่ควรแยกจากกันได้


1
นี่เป็นปัญหาตรงข้ามกับปัญหาที่อธิบายไว้ในstackoverflow.com/questions/7104578/…แม้ว่าคำตอบอาจจะเกี่ยวข้องกัน ทั้งสองคำถามเกี่ยวกับความเป็นเจ้าของ แต่ตัวอย่างนั้นบอกเป็นนัยว่าวัตถุระดับบนสุดไม่ใช่ของตัวเอง
Wes

1
สิ่งที่ฉันสงสัยเกี่ยวกับ สำหรับกรณีการใช้งานที่กำหนดวิธีการแก้ปัญหาของคุณดูเหมือนดี แต่จะเกิดอะไรขึ้นถ้าความสัมพันธ์คือการรวมมากกว่าการจัดองค์ประกอบ? ยังคงดิ้นรนที่จะคิดออกว่าแนวปฏิบัติที่ดีที่สุดคืออะไรที่นี่ ... นอกจากนี้การแก้ปัญหานี้บ่งบอกถึงเพียงการสร้างความสัมพันธ์เช่นบุคคลที่มีอยู่ถูกว่าจ้างหรือสร้างวัตถุบุคคลหรือไม่?
Jakob O.

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

ฉันแบ่งคำถามออกเป็นคำตอบและคำถาม
Wes

คำตอบ:


152

สิ่งที่คุณทำถูกต้อง โดยทั่วไปอาจมี URI จำนวนมากในทรัพยากรเดียวกัน - ไม่มีกฎที่บอกว่าคุณไม่ควรทำเช่นนั้น

และโดยทั่วไปคุณอาจจำเป็นต้องเข้าถึงรายการโดยตรงหรือเป็นส่วนย่อยของสิ่งอื่น - ดังนั้นโครงสร้างของคุณจึงสมเหตุสมผลสำหรับฉัน

เพียงเพราะพนักงานสามารถเข้าถึงได้ภายใต้แผนก:

company/{companyid}/department/{departmentid}/employees

ไม่ได้หมายความว่าพวกเขาไม่สามารถเข้าถึงได้ภายใต้ บริษัท ด้วย:

company/{companyid}/employees

ซึ่งจะส่งคืนพนักงานสำหรับ บริษัท นั้น ขึ้นอยู่กับสิ่งที่ลูกค้าต้องการของคุณ - นั่นคือสิ่งที่คุณควรออกแบบ

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


11
นี่เป็นการชี้ให้เห็นถึงจิตวิญญาณของ RESTful ไม่มีกฎเกณฑ์ที่บอกว่าคุณควรหรือไม่ควรทำหากคุณเพียงพิจารณาทรัพยากรที่มีความหมายก่อน แต่ยิ่งไปกว่านั้นฉันสงสัยว่าอะไรคือวิธีปฏิบัติที่ดีที่สุดสำหรับการไม่ทำซ้ำรหัสในสถานการณ์ดังกล่าว
abookyun

13
@abookyun หากคุณต้องการทั้งสองเส้นทางจากนั้นรหัสคอนโทรลเลอร์ที่ซ้ำกันระหว่างพวกเขาสามารถแยกเป็นวัตถุบริการ
bgcode

สิ่งนี้ไม่เกี่ยวข้องกับ REST ส่วนที่เหลือไม่สนใจว่าคุณจัดโครงสร้างส่วนเส้นทางของ URL ของคุณอย่างไรทั้งหมดที่ห่วงใยนั้นถูกต้องหวังว่า URIs ที่ทนทานจะเป็นเช่นนั้น ...
Redben

ฉันคิดว่าAPIใด ๆที่เซกเมนต์ไดนามิกเป็นตัวระบุเฉพาะทั้งหมดไม่ควรต้องจัดการกับเซกเมนต์ไดนามิกหลายรายการ ( /company/3/department/2/employees/1) หาก api ให้วิธีในการรับแต่ละทรัพยากรการทำการร้องขอแต่ละอย่างนั้นสามารถทำได้ในไลบรารีฝั่งไคลเอ็นต์หรือเป็นจุดสิ้นสุดแบบครั้งเดียวที่ใช้รหัสซ้ำ
สูงสุด

1
ในขณะที่ไม่มีข้อห้ามฉันคิดว่ามันสวยงามกว่าที่จะมีทางไปสู่ทรัพยากรเพียงทางเดียว - ทำให้แบบจำลองทางจิตทั้งหมดง่ายขึ้น ฉันยังต้องการให้ URIs ไม่เปลี่ยนประเภททรัพยากรหากมีการซ้อนกัน ตัวอย่างเช่น/company/*ควรส่งคืนทรัพยากรของ บริษัท เท่านั้นและไม่เปลี่ยนประเภททรัพยากรเลย สิ่งนี้ไม่มีการระบุโดย REST - โดยทั่วไปจะระบุไว้ไม่ดี - เพียงแค่การตั้งค่าส่วนตัว
kashif

174

ฉันได้ลองกลยุทธ์การออกแบบทั้งสอง - จุดสิ้นสุดซ้อนและไม่ซ้อนกัน ฉันพบว่า:

  1. หากทรัพยากรที่ซ้อนอยู่มีคีย์หลักและคุณไม่มีคีย์หลักของมันโครงสร้างที่ซ้อนกันต้องการให้คุณรับแม้ว่าระบบจะไม่ต้องการมันจริง

  2. จุดสิ้นสุดแบบซ้อนโดยทั่วไปต้องการจุดสิ้นสุดซ้ำซ้อน กล่าวอีกนัยหนึ่งคุณมักจะไม่ต้องการจุดปลายทางเพิ่มเติม / พนักงานเพื่อให้คุณสามารถรับรายชื่อพนักงานในแผนกต่างๆ หากคุณมี / พนักงาน บริษัท / แผนก / พนักงานซื้ออะไรกันแน่?

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

  4. บางครั้งทรัพยากรอาจมีผู้ปกครองหลายประเภท ส่งผลให้หลายจุดปลายทั้งหมดส่งคืนทรัพยากรเดียวกัน

  5. จุดสิ้นสุดซ้ำซ้อนทำให้เอกสารยากต่อการเขียนและทำให้ API ยากต่อการเรียนรู้

กล่าวโดยสรุปแล้วการออกแบบที่ไม่ซ้อนกันนั้นดูเหมือนว่าจะช่วยให้สกีมาจุดปลายมีความยืดหยุ่นและง่ายขึ้น


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

6
ดูเหมือนว่าคุณจะแสดงรายการข้อเสียบางส่วนว่าเป็น Upside "เพียงอัดพารามิเตอร์มากขึ้นในจุดเดียว" ทำให้ API ยากต่อการจัดทำเอกสารและการเรียนรู้ไม่ใช่วิธีอื่น ๆ ;-)
Drenmi

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

3
@Scottm - ข้อเสียอย่างหนึ่งของทรัพยากรที่ซ้อนอยู่ที่ฉันเจอคืออาจทำให้ข้อมูลที่ไม่ถูกต้องกลับมาถ้ารหัสทรัพยากรหลักไม่ถูกต้อง / ไม่ตรงกัน สมมติว่าไม่มีปัญหาการให้สิทธิ์มันจะเหลือสำหรับการใช้ api เพื่อตรวจสอบว่าทรัพยากรที่ซ้อนกันนั้นเป็นลูกของทรัพยากรหลักที่ผ่านไปแล้ว หากการตรวจสอบนี้ไม่ได้รับการเข้ารหัสการตอบสนองของ api อาจไม่ถูกต้องซึ่งนำไปสู่ความเสียหาย คุณคิดยังไง?
Andy Dufresne

1
คุณไม่จำเป็นต้องใช้รหัส parent ระดับกลางหากทรัพยากรปลายทางทั้งหมดมีรหัสเฉพาะ ตัวอย่างเช่นในการรับพนักงานโดยใช้ ID คุณจะได้รับ / บริษัท / แผนก / พนักงาน / {empId} หรือรับพนักงานทั้งหมดใน บริษัท 123 คุณมี GET / บริษัท / 123 / แผนก / พนักงาน / การรักษาเส้นทางลำดับชั้นทำให้ชัดเจนมากขึ้นว่า คุณสามารถเข้าถึงทรัพยากรระดับกลางเพื่อกรอง / สร้าง / แก้ไขและช่วยในการค้นพบในความคิดของฉัน
PaulG

77

ฉันได้ย้ายสิ่งที่ฉันทำจากคำถามไปเป็นคำตอบที่มีคนมากกว่าที่จะเห็นมัน

สิ่งที่ฉันทำคือการมีจุดปลายการสร้างที่จุดปลายซ้อน, จุดสิ้นสุดแบบบัญญัติสำหรับการแก้ไขหรือการค้นหารายการไม่ได้อยู่ที่แหล่งซ้อนไม่ได้อยู่ที่ทรัพยากรที่ซ้อนกัน

ดังนั้นในตัวอย่างนี้ (เพียงแสดงรายการจุดสิ้นสุดที่เปลี่ยนทรัพยากร)

  • POST /companies/ สร้าง บริษัท ใหม่ส่งคืนลิงก์ไปยัง บริษัท ที่สร้างขึ้น
  • POST /companies/{companyId}/departments เมื่อแผนกถูกสร้างขึ้นแผนกใหม่จะคืนลิงค์ให้ /departments/{departmentId}
  • PUT /departments/{departmentId} ปรับเปลี่ยนแผนก
  • POST /departments/{deparmentId}/employees สร้างพนักงานใหม่คืนลิงค์ให้ /employees/{employeeId}

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


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

ฉันเดาว่าคุณใช้POSTความหมายPUTและอย่างอื่น
Gerardo Lima

จริงๆแล้วไม่ทราบว่าฉันไม่ได้ใช้รหัสที่กำหนดไว้ล่วงหน้าสำหรับการสร้างเป็นเซิร์ฟเวอร์ในกรณีนี้มีความรับผิดชอบในการส่งคืนรหัส (ในลิงค์) ดังนั้นการเขียน POST นั้นถูกต้อง (ไม่สามารถดำเนินการได้เหมือนกัน) อย่างไรก็ตามการวางเปลี่ยนทรัพยากรทั้งหมด แต่ยังคงมีอยู่ในสถานที่เดียวกันดังนั้นฉันวางมัน PUT กับ POST เป็นเรื่องที่แตกต่างและขัดแย้งกันเช่นกัน ตัวอย่างเช่นstackoverflow.com/questions/630453/put-vs-post-in-rest
Wes

@Wes แม้ฉันต้องการแก้ไขวิธีกริยาที่จะอยู่ภายใต้ผู้ปกครอง แต่คุณจะเห็นว่าผ่านพารามิเตอร์การสืบค้นสำหรับทรัพยากรระดับโลกเป็นที่ยอมรับกันหรือไม่ ตัวอย่าง: POST / แผนกที่มีพารามิเตอร์การสืบค้น company = company-id
Ayyappa

1
@Mohamad หากคุณคิดว่าวิธีอื่นนั้นง่ายกว่าทั้งในการทำความเข้าใจและการบังคับใช้ข้อ จำกัด คุณสามารถตอบคำถามได้อย่างอิสระ มันเกี่ยวกับการทำให้การทำแผนที่ชัดเจนในกรณีนี้ มันสามารถทำงานกับพารามิเตอร์ แต่จริงๆแล้วมันคือคำถามอะไร อะไรคือวิธีที่ดีที่สุด
Wes

35

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

ในระบบที่ซับซ้อนยิ่งขึ้นสามารถดึงดูด URIs ที่ทำให้ลูกค้าสามารถนำทางผ่านความสัมพันธ์หลายระดับเช่น/customers/1/orders/99/products.อย่างไรก็ตามความซับซ้อนในระดับนี้อาจรักษาได้ยากและไม่ยืดหยุ่นหากความสัมพันธ์ระหว่างทรัพยากรเปลี่ยนไปในอนาคต ให้พยายามทำให้ URIs ง่ายขึ้นแทน เมื่อแอปพลิเคชันมีการอ้างอิงไปยังทรัพยากรคุณควรใช้การอ้างอิงนี้เพื่อค้นหารายการที่เกี่ยวข้องกับทรัพยากรนั้น เคียวรีก่อนหน้านี้สามารถถูกแทนที่ด้วย URI /customers/1/ordersเพื่อค้นหาคำสั่งซื้อทั้งหมดสำหรับลูกค้า 1 จากนั้น/orders/99/productsค้นหาผลิตภัณฑ์ตามลำดับนี้

.

ปลาย

หลีกเลี่ยงการกำหนด URI collection/item/collectionของทรัพยากรที่มีความซับซ้อนมากกว่า


3
การอ้างอิงที่คุณให้นั้นน่าทึ่งพร้อมกับจุดที่คุณโดดเด่นในการไม่สร้าง URI ที่ซับซ้อน
vicco

ดังนั้นเมื่อฉันต้องการสร้างทีมสำหรับผู้ใช้ควรเป็น POST / ทีม (userId ใน thebody) หรือ POST / users /: id / ทีม
coinhndp

@coinhndp สวัสดีคุณควรใช้ POST / ทีมและคุณสามารถรับ userId หลังจากให้สิทธิ์การเข้าถึงโทเค็น ฉันหมายถึงเมื่อคุณสร้างสิ่งที่คุณต้องการรหัสสิทธิ์ใช่มั้ย ฉันไม่ทราบว่าคุณกำลังใช้กรอบงานใด แต่ฉันแน่ใจว่าคุณสามารถรับ userId ในตัวควบคุม API ตัวอย่างเช่น: ใน ASP.NET API โทร RequestContext.Principal จากภายในเมธอดบน ApiController ใน Spring Secirity SecurityContextHolder.getContext (). getAuthentication (). getPrincipal () จะช่วยคุณได้ ใน AWS NodeJS Lambda นั่นคือ cognito: ชื่อผู้ใช้ในวัตถุส่วนหัว
เหงียนลองยาว

ดังนั้นมีอะไรผิดปกติกับ POST / users /: id / teams ฉันคิดว่าขอแนะนำในเอกสาร Microsoft ที่คุณโพสต์ไว้ด้านบน
coinhndp

@coinhndp หากคุณสร้างทีมเป็นผู้ดูแลระบบถือว่าดี แต่ในฐานะผู้ใช้ทั่วไปฉันไม่รู้ว่าทำไมคุณต้องใช้ userId ในเส้นทาง? ฉันคิดว่าเรามี user_A และ user_B คุณคิดอย่างไรถ้า user_A สามารถสร้างทีมใหม่สำหรับ user_B ถ้า user_A โทร POST / users / user_B / ทีม ดังนั้นไม่จำเป็นต้องส่งรหัสผู้ใช้ในกรณีนี้ userId สามารถรับได้หลังจากการให้สิทธิ์ แต่ teams /: id / project เป็นการดีที่จะสร้างความสัมพันธ์ระหว่างทีมและโครงการเช่น
เหงียน

10

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

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

ทำไมเป็นเช่นนั้น เท่าที่ฉันทราบ API "RESTful" จะสามารถเรียกดูได้ (คุณรู้ว่า ... "Hypermedia ในฐานะ Engine of Application State") ดังนั้นไคลเอ็นต์ API ไม่สนใจว่า URL ของคุณจะเป็นอย่างไรตราบใดที่ URL นั้น ถูกต้อง (ไม่มี SEO, ไม่มีมนุษย์คนใดที่จำเป็นต้องอ่าน "URL ที่เป็นมิตร" เหล่านั้นยกเว้นอาจใช้เพื่อการดีบัก ... )

ความดี / ความเข้าใจของ URL ที่อยู่ใน REST API นั้นน่าสนใจสำหรับคุณในฐานะนักพัฒนา API ไม่ใช่ลูกค้า API เช่นเดียวกับชื่อของตัวแปรในรหัสของคุณ

สิ่งที่สำคัญที่สุดคือลูกค้า API ของคุณรู้วิธีตีความประเภทสื่อของคุณ ตัวอย่างเช่นรู้ว่า:

  • ประเภทสื่อของคุณมีคุณสมบัติลิงก์ที่แสดงรายการลิงก์ที่เกี่ยวข้อง / มีอยู่
  • แต่ละลิงก์ถูกระบุโดยความสัมพันธ์ (เช่นเดียวกับเบราว์เซอร์รู้ว่าลิงก์ [rel = "stylesheet"] หมายถึงสไตล์ชีทหรือ rel = favico เป็นลิงค์ไปยัง favicon ... )
  • และรู้ว่าความสัมพันธ์เหล่านั้นมีความหมายอย่างไร ("บริษัท " หมายถึงรายชื่อ บริษัท "ค้นหา" หมายถึง URL ของ templated สำหรับการค้นหาในรายการทรัพยากร "แผนก" หมายถึงแผนกของทรัพยากรปัจจุบัน)

ด้านล่างเป็นตัวอย่างการแลกเปลี่ยน HTTP (เนื้อความอยู่ใน yaml เนื่องจากง่ายต่อการเขียน):

ขอร้อง

GET / HTTP/1.1
Host: api.acme.io
Accept: text/yaml, text/acme-mediatype+yaml

การตอบสนอง:รายการลิงก์ไปยังทรัพยากรหลัก (บริษัท ผู้คนอะไรก็ตาม ... )

HTTP/1.1 200 OK
Date: Tue, 05 Apr 2016 15:04:00 GMT
Last-Modified: Tue, 05 Apr 2016 00:00:00 GMT
Content-Type: text/acme-mediatype+yaml

# body: this is your API's entrypoint (like a homepage)  
links:
  # could be some random path https://api.acme.local/modskmklmkdsml
  # the only thing the API client cares about is the key (or rel) "companies"
  companies: https://api.acme.local/companies
  people: https://api.acme.local/people

คำขอ:ลิงก์ไปยัง บริษัท ต่างๆ (โดยใช้ body.links.com การตอบกลับก่อนหน้านี้)

GET /companies HTTP/1.1
Host: api.acme.local
Accept: text/yaml, text/acme-mediatype+yaml

การตอบสนอง:รายการบางส่วนของ บริษัท (ภายใต้รายการ) ทรัพยากรมีลิงค์ที่เกี่ยวข้องเช่นลิงก์เพื่อรับคู่ของ บริษัท ถัดไป (body.links.next) ลิงก์อื่น (templated) เพื่อค้นหา (body.links.search)

HTTP/1.1 200 OK
Date: Tue, 05 Apr 2016 15:06:00 GMT
Last-Modified: Tue, 05 Apr 2016 00:00:00 GMT
Content-Type: text/acme-mediatype+yaml

# body: representation of a list of companies
links:
  # link to the next page
  next: https://api.acme.local/companies?page=2
  # templated link for search
  search: https://api.acme.local/companies?query={query} 
# you could provide available actions related to this resource
actions:
  add:
    href: https://api.acme.local/companies
    method: POST
items:
  - name: company1
    links:
      self: https://api.acme.local/companies/8er13eo
      # and here is the link to departments
      # again the client only cares about the key department
      department: https://api.acme.local/companies/8er13eo/departments
  - name: company2
    links:
      self: https://api.acme.local/companies/9r13d4l
      # or could be in some other location ! 
      department: https://api2.acme.local/departments?company=8er13eo

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


7
"ความดี / ความเข้าใจของ URL ที่อยู่ใน REST API นั้นน่าสนใจสำหรับคุณในฐานะนักพัฒนา API ไม่ใช่ไคลเอนต์ API เช่นเดียวกับชื่อตัวแปรในรหัสของคุณ" ทำไมสิ่งนี้ถึงไม่น่าสนใจ? สิ่งนี้สำคัญมากถ้าใครก็ตาม แต่คุณเองก็ใช้ API เช่นกัน นี่เป็นส่วนหนึ่งของประสบการณ์ผู้ใช้ดังนั้นฉันจะบอกว่ามันสำคัญมากที่จะเข้าใจได้ง่ายสำหรับนักพัฒนาไคลเอ็นต์ API การทำสิ่งต่าง ๆ ให้เข้าใจง่ายยิ่งขึ้นโดยการเชื่อมโยงแหล่งข้อมูลอย่างชัดเจนเป็นโบนัส (ระดับ 3 ใน URL ที่คุณให้) ทุกอย่างควรเป็นสัญชาตญาณและมีเหตุผลด้วยความสัมพันธ์ที่ชัดเจน
Joakim

1
@Joakim หากคุณกำลังทำ API พักผ่อนระดับ 3 (Hypertext เป็น Engine ของ Application State) ดังนั้นโครงสร้างเส้นทางของ URL จะไม่สนใจลูกค้าอย่างแน่นอน (ตราบใดที่มันถูกต้อง) หากคุณไม่ได้มุ่งเป้าไปที่ระดับ 3 แล้วใช่มันเป็นสิ่งสำคัญและควรจะคาดเดาได้ แต่ REST ที่แท้จริงคือระดับ 3 บทความที่ดี: martinfowler.com/articles/richardsonMaturityModel.html
redben

4
ฉันคัดค้านการสร้าง API หรือ UI ที่ไม่เป็นมิตรต่อผู้ใช้ ระดับ 3 หรือไม่ฉันเห็นด้วยกับการเชื่อมโยงทรัพยากรเป็นความคิดที่ดี แต่การแนะนำให้ทำเช่นนั้น "ทำให้เป็นไปได้ที่จะเปลี่ยนรูปแบบ URL" ให้พ้นจากความเป็นจริงและวิธีที่ผู้คนใช้ API ดังนั้นจึงเป็นคำแนะนำที่ไม่ดี แต่มั่นใจในสิ่งที่ดีที่สุดของโลกทุกคนจะอยู่ที่ระดับ 3 REST ฉันรวมการเชื่อมโยงหลายมิติและใช้รูปแบบ URL ที่มนุษย์เข้าใจได้ ระดับ 3 ไม่ได้แยกอดีตและหนึ่งควรระวังในความคิดของฉัน แม้ว่าบทความที่ดี :)
Joakim

แน่นอนว่าเราควรใส่ใจในเรื่องของการบำรุงรักษาและความกังวลอื่น ๆ ฉันคิดว่าคุณพลาดประเด็นคำตอบของฉัน: วิธีที่ URL หน้าตาไม่สมควรได้รับการคิดมากและคุณควร "เลือกและติดอยู่กับที่ / สอดคล้อง "ตามที่ฉันพูดในคำตอบ และในกรณีของ REST API อย่างน้อยความคิดของฉัน friendlyness ผู้ใช้ไม่ได้ใน url มันเป็นส่วนใหญ่ใน (ประเภทสื่อ) อย่างไรก็ตามผมหวังว่าคุณจะเข้าใจจุดของฉัน :)
redben

9

ฉันไม่เห็นด้วยกับเส้นทางแบบนี้

GET /companies/{companyId}/departments

หากคุณต้องการได้รับแผนกฉันคิดว่ามันจะดีกว่าที่จะใช้ทรัพยากร / แผนก

GET /departments?companyId=123

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

GET /departments?companyId=123

สำหรับการค้นหาทุกประเภทเช่น

GET /departments?name=xxx
GET /departments?companyId=123&name=xxx
etc.

หากคุณต้องการสร้างแผนก

POST /departments

ควรใช้ทรัพยากรและหน่วยงานร้องขอควรมี ID บริษัท (หากแผนกสามารถเชื่อมโยงกับ บริษัท เดียวเท่านั้น)


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

นี่คือสิ่งที่ฉันพูดถ้าคุณต้องการดึงแผนกต่างๆมาใช้หมายความว่าคุณจะใช้จุดสิ้นสุดแผนก /
Maxime Laval

2
นอกจากนี้อาจเหมาะสมที่จะอนุญาตให้แผนกต่างๆรวมอยู่ในการโหลดแบบสันหลังยาวเมื่อดึง บริษัท เช่นGET /companies/{companyId}?include=departmentsเนื่องจากจะทำให้ทั้ง บริษัท และแผนกต่างๆสามารถดึงข้อมูลในคำขอ HTTP เดียว เศษส่วนทำได้ดีมาก
Matthew Daly

1
เมื่อคุณตั้งค่า acls คุณอาจต้องการ จำกัด/departmentsendpoint ให้เข้าถึงได้โดยผู้ดูแลระบบเท่านั้นและให้แต่ละ บริษัท เข้าถึงแผนกของตนเองผ่าน '/ companies / {companyId} / แผนก'
Cuzox

@MatthewDaly OData ก็ทำเช่นนั้นได้ด้วยการขยาย $
Rob Grant

1

Rails มอบทางออกให้กับสิ่งนี้: การทำรังแบบตื้นรังตื้น

ฉันคิดว่านี่เป็นสิ่งที่ดีเพราะเมื่อคุณจัดการกับทรัพยากรที่รู้จักโดยตรงไม่จำเป็นต้องใช้เส้นทางที่ซ้อนกันดังที่ได้อธิบายไว้ในคำตอบอื่น ๆ ที่นี่

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