REST API DESIGN - รับทรัพยากรผ่าน REST ที่มีพารามิเตอร์ต่างกัน แต่มีรูปแบบ URL เดียวกัน


92

ฉันมีคำถามเกี่ยวกับการออกแบบ REST url ฉันพบโพสต์ที่เกี่ยวข้องบางส่วนที่นี่: การนำเสนอRESTful ที่แตกต่างกันของทรัพยากรเดียวกันและที่นี่: RESTful url to GET resource ตามช่องต่างๆแต่คำตอบยังไม่ชัดเจนว่าแนวทางปฏิบัติที่ดีที่สุดคืออะไรและเพราะเหตุใด นี่คือตัวอย่าง

ฉันมี URL REST สำหรับแสดงทรัพยากร "ผู้ใช้" ฉันสามารถรับผู้ใช้ด้วยรหัสหรือที่อยู่อีเมลได้ แต่การแสดง URL ยังคงเหมือนเดิมสำหรับทั้งสองอย่าง ผ่านบล็อกและหนังสือมากมายฉันเห็นว่าผู้คนทำสิ่งนี้ในรูปแบบต่างๆมากมาย ตัวอย่างเช่น

อ่านแบบฝึกหัดนี้ในหนังสือและที่ไหนสักแห่งใน stackoverflow (ดูเหมือนจะหาลิงค์ไม่เจออีกแล้ว)

GET /users/id={id}
GET /users/email={email}

อ่านแบบฝึกหัดนี้ในบล็อกจำนวนมาก

GET /users/{id}
GET /users/email/{email}

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

GET /users?id={id}
GET /users?email={email}

คำถามของฉันคือจากแนวทางปฏิบัติทั้งหมดนี้ข้อใดเหมาะสมที่สุดสำหรับนักพัฒนาที่ใช้ apis และเพราะเหตุใด ฉันเชื่อว่าไม่มีกฎใด ๆ ที่กำหนดไว้ในเรื่องการออกแบบ REST url และรูปแบบการตั้งชื่อ แต่ฉันแค่อยากรู้ว่าฉันควรใช้เส้นทางใดเพื่อช่วยให้นักพัฒนาเข้าใจ apis ได้ดีขึ้น

ทุกคนช่วยชื่นชม!


1
ฉันรู้ว่านี่เก่าไปหน่อย แต่กำลังมองหาแหล่งข้อมูลที่คล้ายกันฉันพบคำถามนี้และคำถามที่คุณกำลังมองหา ฉันเชื่อว่านี่คือสิ่งนี้stackoverflow.com/a/9743414/468327
Joel Berger

คำตอบ:


104

จากประสบการณ์ของฉันGET /users/{id} GET /users/email/{email}เป็นแนวทางที่พบบ่อยที่สุด ฉันยังคาดหวังว่าวิธีการส่งคืน 404 Not Found หากไม่มีผู้ใช้กับสิ่งที่ให้มาidหรือemail. ฉันคงไม่แปลกใจที่เห็นGET /users/id/{id}เช่นกัน (ในความคิดของฉันมันซ้ำซ้อน)

ความคิดเห็นเกี่ยวกับแนวทางอื่น ๆ

  1. GET /users/id={id} GET /users/email={email}
    • ฉันไม่คิดว่าจะได้เห็นสิ่งนี้และถ้าฉันได้เห็นมันคงจะสับสนมาก เกือบจะเหมือนกับว่าพยายามเลียนแบบพารามิเตอร์การสืบค้นด้วยพารามิเตอร์เส้นทาง
  2. GET /users?id={id} GET /users?email={email}
    • ฉันคิดว่าคุณตอกตะปูบนหัวเมื่อคุณพูดถึงโดยใช้พารามิเตอร์การค้นหาสำหรับการกรอง
    • มันสมเหตุสมผลหรือไม่ที่จะเรียกทรัพยากรนี้ด้วยทั้ง an idและemail(เช่นGET /users?id={id}&email={email}) ถ้าไม่ฉันจะไม่ใช้วิธีการทรัพยากรเดียวเช่นนี้
    • ผมคาดว่าวิธีนี้สำหรับการดึงรายชื่อของผู้ใช้ที่มีพารามิเตอร์การค้นหาตัวเลือกสำหรับการกรอง แต่ฉันจะไม่คาดหวังid, emailหรือระบุเฉพาะใด ๆ จะอยู่ในหมู่พารามิเตอร์ ตัวอย่างเช่น: GET /users?status=BANNEDอาจส่งคืนรายชื่อผู้ใช้ที่ถูกแบน

ลองดูคำตอบนี้จากคำถามที่เกี่ยวข้อง


ขอบคุณสำหรับข้อมูล จริงๆแล้วคุณพูดถูก ดูเหมือนว่าฉันอ่าน # 1 ในหนังสือ "RESTful java with Jax-rs" แต่ค่อนข้างไม่ตรงกับบริบท แต่ฉันจำได้อย่างชัดเจนว่าอ่านว่าเป็นคำตอบสำหรับคำถามหนึ่งใน stackoverflow (เชื่อฉันเมื่อฉันบอกว่าฉันพยายามอย่างมากที่จะหาลิงค์นั้นเพื่อพิสูจน์ให้เพื่อนร่วมงานของฉันเห็นด้วย :)) และ # 2 คือสิ่งที่ฉันเป็น กำลังมองหา. ข้อเสนอแนะบางประการเกี่ยวกับการออกแบบ ขอบคุณ!
shahshi15

PS: ฉันไม่แน่ใจว่าการโพสต์สิ่งนี้ผิดกฎที่นี่หรือไม่ แต่คุณอาจให้ความสำคัญกับคำถามอื่น ๆ ของฉันได้เช่นกัน? กรุณา? :) stackoverflow.com/questions/20508008/…
shahshi15

เพียงเพื่อชี้แจงเกี่ยวกับคำแถลงของคุณเกี่ยวกับความซ้ำซ้อน/users/id/{id}สิ่งนี้ช่วยให้สามารถใช้งานได้เพิ่มเติมเพียงแค่อนุญาตให้เข้าถึงทรัพยากรเดียวผ่านตัวระบุหลายตัว (id, guid, name) ยังมีคำตอบที่นี่
Daniel Dubovski

4
คำตอบของฉันคือวิธีที่เหมาะสมในการอ้างอิงผู้ใช้ที่ต้องการเช่น / users / {id} หากคุณต้องการค้นหาผู้ใช้โดยใช้ที่อยู่อีเมลเฉพาะที่ไม่ใช่ตัวระบุเฉพาะสำหรับผู้ใช้ฉันจะทำ / users? email = {email} เนื่องจากเป็นวิธีการกรองกลุ่มผู้ใช้ไม่ใช่ระบุทรัพยากรเฉพาะจากทรัพยากร ตัวระบุเป็น / users / {id} คือ
Kevin M

ตอบโจทย์มาก! Thumbsup สำหรับมัน สิ่งเดียวที่ฉันอยากแนะนำให้ทำคือเปลี่ยน API ของคุณเล็กน้อยเนื่องจาก REST ควรมีชื่อเป็นศูนย์กลางดังนั้นการแมปทรัพยากรของคุณควรเป็นดังนี้: GET /user/1234ไม่ใช่GET /users/123
Sammy

38

เมื่อพิจารณาในทางปฏิบัติแล้วคุณมีกลุ่มผู้ใช้:

/users   # this returns many

ผู้ใช้แต่ละคนมีตำแหน่งทรัพยากรเฉพาะ:

/users/{id}    # this returns one

คุณยังมีอีกหลายวิธีในการค้นหาผู้ใช้:

/users?email={email}
/users?name=*bob*

เนื่องจากพารามิเตอร์เหล่านี้เป็นพารามิเตอร์การสืบค้นถึง / ผู้ใช้ทั้งหมดจึงควรส่งคืนรายการทั้งหมด .. แม้ว่าจะเป็นรายการ 1 ก็ตาม

ฉันเขียนบล็อกโพสต์เกี่ยวกับการออกแบบ RESTful API ในเชิงปฏิบัติที่นี่ซึ่งพูดถึงเรื่องนี้เหนือสิ่งอื่นใดที่นี่: http://www.vinaysahni.com/best-practices-for-a-pragmatic-restful-api


ขอบคุณสำหรับคำตอบ vinay แต่ถ้าเราคิดในมุมมองอื่น {email} ก็เหมือนกับ {id} เสมอที่จะส่งกลับผลลัพธ์กลับ หากเรากำลังค้นหาจริงๆทำไมไม่ใช้? id = {id} เช่นเดียวกับอีเมล? ฉันสงสัยว่ามีความสอดคล้องกันหรือไม่ PS: ใหม่สำหรับ stackoverflow ไม่ทราบว่าฉันสามารถตอบได้เพียงคำตอบเดียว แต่ขอบคุณสำหรับการตอบกลับของคุณ! ชื่นชมมัน. บางทีคุณอาจช่วยฉันด้วยสิ่งนี้ได้เช่นกัน: stackoverflow.com/questions/20508008/…
shahshi15

7
นี่คือส่วนที่ "การออกแบบ" ของการออกแบบ API เข้ามามีบทบาท ทรัพยากรของคุณควรมีสถานที่เฉพาะ สถานที่ตั้งอยู่ที่ไหน สถานที่ตั้งโดย id? ถ้าเป็นเช่นนั้นคุณจะไม่ "ค้นหา" ด้วย id แสดงว่าคุณ "ได้รับ" ตาม id แต่คุณค้นหาทุกอย่าง แน่นอนไม่มีกฎที่กำหนดไว้ที่นี่ มันเป็นแค่มุมมอง :)
Vinay Sahni

6
ฉันขอโต้แย้งว่าวิธีนี้ API ของคุณมีเสถียรภาพมากขึ้น คุณรู้จริงๆว่ารหัสของคุณไม่ซ้ำกัน แต่คุณแน่ใจจริงๆเกี่ยวกับที่อยู่อีเมลหรือไม่? แม้ว่าจะไม่ซ้ำกัน แต่ก็อาจไม่ถาวรเนื่องจากผู้ใช้สามารถเปลี่ยนได้ ดังนั้น / users? email = {email} ทำให้ชัดเจนว่านี่คือข้อความค้นหาและไม่สามารถเข้าถึงทรัพยากรที่มีตัวระบุสิทธิ์ได้
lex82

ฉันเชื่อว่านี่เป็นคำตอบที่ถูกต้องกว่า การกรองคอลเล็กชันตามที่อยู่อีเมลอาจใช้สัญลักษณ์แทนดังนั้นจะไม่ส่งคืนเพียงผลลัพธ์เดียวเสมอไป
Kevin M

@VinaySahni คุณจะพูดอย่างไรเกี่ยวกับรูปแบบเช่น: /user?by=email&email="abc@pqr.com "/ user? by = id & id =" xashkhx "/ users? filterA =" a "& filterB =" b "(พหูพจน์ สำหรับผู้ใช้หลายคน)
Shasak

2

เกี่ยวกับทรัพยากรของผู้ใช้

บนเส้นทางนี้/usersคุณจะได้รับชุดทรัพยากรของผู้ใช้คืนเสมอ

บนเส้นทางที่/users/[user_id]คุณสามารถคาดหวังได้หลายสิ่งที่จะเกิดขึ้น:

  1. คุณควรได้รับทรัพยากรเดี่ยวที่แสดงถึงทรัพยากรผู้ใช้ด้วยตัวระบุ [user_id] หรือ
  2. ไม่พบการตอบสนอง404หากไม่มีผู้ใช้ที่มี id [user_id] อยู่หรือ
  3. 401ต้องห้ามหากคุณไม่ได้รับอนุญาตให้เข้าถึงทรัพยากรผู้ใช้ที่ร้องขอ

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

คุณสามารถสืบค้นเส้นทาง/usersด้วยพารามิเตอร์การสืบค้น ( GETพารามิเตอร์) สิ่งนี้จะส่งคืนคอลเล็กชันที่มีผู้ใช้ที่ตรงตามเกณฑ์ที่ร้องขอ คอลเล็กชันที่ส่งคืนควรมีรีซอร์สผู้ใช้ทั้งหมดที่มีพา ธ รีซอร์สระบุในการตอบ

พารามิเตอร์อาจเป็นฟิลด์ใดก็ได้ที่มีอยู่ในทรัพยากรของคอลเล็กชัน firstName, lastName,id

เกี่ยวกับอีเมล

อีเมลอาจเป็นทรัพยากรหรือคุณสมบัติ / ฟิลด์ของทรัพยากรผู้ใช้

- อีเมลเป็นทรัพย์สินของผู้ใช้:

หากฟิลด์เป็นคุณสมบัติของผู้ใช้การตอบสนองของผู้ใช้จะมีลักษณะดังนี้:

{ 
  id: 1,
  firstName: 'John'
  lastName: 'Doe'
  email: 'john.doe@example.com'
  ...
}

ซึ่งหมายความว่าไม่มีปลายทางพิเศษสำหรับอีเมล /users?email=john.doe@example.comแต่ตอนนี้คุณสามารถค้นหาผู้ใช้ทางอีเมลโดยการส่งคำขอต่อไปนี้: ซึ่ง (สมมติว่าอีเมลไม่ซ้ำกันสำหรับผู้ใช้) จะส่งคืนคอลเล็กชันที่มีรายการผู้ใช้หนึ่งรายการที่ตรงกับอีเมล

- ส่งอีเมลเป็นทรัพยากร:

แต่ถ้าอีเมลจากผู้ใช้ยังเป็นแหล่งข้อมูล จากนั้นคุณสามารถทำให้ API ที่ซึ่ง/users/[user_id]/emailsผลตอบแทนที่คอลเลกชันของที่อยู่อีเมลสำหรับผู้ใช้ที่มี user_idID /users/[user_id]/emails/[email_id]ส่งคืนอีเมลของผู้ใช้ด้วย user_id และ ['email_id'] สิ่งที่คุณใช้เป็นตัวระบุนั้นขึ้นอยู่กับคุณ แต่ฉันจะยึดติดกับจำนวนเต็ม คุณสามารถลบอีเมลจากผู้ใช้ได้โดยส่งDELETEคำขอไปยังเส้นทางที่ระบุอีเมลที่คุณต้องการลบ ตัวอย่างเช่นDELETEใน/users/[user_id]/emails/[email_id]จะลบอีเมลที่มี email_id ซึ่งเป็นของผู้ใช้ที่มี user_id เป็นไปได้มากว่าผู้ใช้รายนั้นเท่านั้นที่ได้รับอนุญาตให้ดำเนินการลบนี้ ผู้ใช้รายอื่นจะได้รับการตอบสนอง 401

หากผู้ใช้สามารถมีที่อยู่อีเมลเดียวคุณสามารถใช้/users/[user_id]/email สิ่งนี้จะส่งคืนทรัพยากรแบบซิงเกิลตัน ผู้ใช้สามารถอัปเดตที่อยู่อีเมลของตนได้โดยPUTใส่ที่อยู่อีเมลที่ url นั้น

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