RESTful API: คำกริยา HTTP กับ URL ที่แชร์หรือเฉพาะ


25

ในขณะที่สร้างRESTful APIฉันควรใช้ HTTP Verbs บน URL เดียวกัน (เมื่อเป็นไปได้) หรือฉันควรสร้าง URL เฉพาะสำหรับแต่ละการกระทำ

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

GET     /items      # Read all items
GET     /items/:id  # Read one item
POST    /items      # Create a new item
PUT     /items/:id  # Update one item
DELETE  /items/:id  # Delete one item

หรือด้วย URL เฉพาะเช่น:

GET     /items            # Read all items
GET     /item/:id         # Read one item
POST    /items/new        # Create a new item
PUT     /item/edit/:id    # Update one item
DELETE  /item/delete/:id  # Delete one item

คำตอบ:


46

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

เพียงแค่ดูDELETE /item/delete/:idคุณวางข้อมูลเดียวกันสองครั้งในคำขอเดียวกัน สิ่งนี้ไม่จำเป็นและควรหลีกเลี่ยง โดยส่วนตัวฉันจะสับสนกับเรื่องนี้ API รองรับDELETEคำขอจริงหรือไม่ จะทำอย่างไรถ้าฉันใส่deleteURL และใช้กริยา HTTP อื่นแทน มันจะจับคู่กับอะไรไหม? ถ้าเป็นเช่นนั้นจะเลือกอันไหน? ในฐานะลูกค้าของ API ที่ออกแบบมาอย่างถูกต้องฉันไม่ควรถามคำถามเช่นนั้น

บางทีคุณอาจต้องการมันเพื่อสนับสนุนลูกค้าที่ไม่สามารถออกDELETEหรือPUTร้องขอได้ หากเป็นกรณีนี้ฉันจะส่งข้อมูลนี้ในส่วนหัว HTTP API บางตัวใช้X-HTTP-Method-Overrideส่วนหัวสำหรับวัตถุประสงค์เฉพาะนี้ (ซึ่งฉันคิดว่าค่อนข้างน่าเกลียดอยู่ดี) แน่นอนฉันจะไม่วางคำกริยาในเส้นทางแม้ว่า

ไปเพื่อ

GET     /items      # Read all items
GET     /items/:id  # Read one item
POST    /items      # Create a new item
PUT     /items/:id  # Update one item
DELETE  /items/:id  # Delete one item

สิ่งที่สำคัญเกี่ยวกับคำกริยาคือพวกมันถูกนิยามไว้อย่างดีในสเปค HTTP และการใช้กฎเหล่านี้ช่วยให้คุณสามารถใช้แคชพร็อกซีและเครื่องมืออื่น ๆ ภายนอกแอปพลิเคชันของคุณที่เข้าใจความหมายของ HTTP . โปรดทราบว่าเหตุผลที่คุณควรหลีกเลี่ยงการมีใน URL ของคุณไม่ได้เกี่ยวกับ RESTful API ที่ต้องใช้ URL ที่อ่านได้ มันเกี่ยวกับการหลีกเลี่ยงความคลุมเครือที่ไม่จำเป็น

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

โปรดทราบว่าสงบ API อย่างแท้จริงไม่ควรจะต้องเขียนโปรแกรมเพื่ออ่านเอกสารที่กว้างขวางของ URL ที่ใช้ได้ตราบเท่าที่คุณเป็นไปตาม HATEOAS (Hypertext เป็นเครื่องยนต์ของแอพลิเคชันของรัฐ) หลักการซึ่งเป็นหนึ่งในสมมติฐานหลักของส่วนที่เหลือ ลิงก์สามารถเข้าใจได้อย่างสมบูรณ์กับมนุษย์ตราบใดที่แอปพลิเคชันไคลเอนต์สามารถเข้าใจและใช้ลิงก์เหล่านั้นเพื่อพิจารณาการเปลี่ยนสถานะแอปพลิเคชันที่เป็นไปได้


4
ในกรณีที่ไม่มีPUTและDELETEฉันชอบที่จะเพิ่มไปยังเส้นทางไม่แตกต่างกับสตริงแบบสอบถาม ไม่ใช่การแก้ไขสตริงการสืบค้นสำหรับการดำเนินการที่มีอยู่ มันเป็นการดำเนินการแยกต่างหาก
Robert Harvey

4
@ RobertHarvey ในกรณีนี้ฉันจะเรียกมันว่าแฮ็ค อย่างที่คุณพูดมันเป็นการดำเนินการและนั่นไม่ใช่สิ่งที่ฉันใส่ในเส้นทางเมื่อออกแบบ API ที่มุ่งมั่นที่จะสงบ วางไว้ในสตริงแบบสอบถามก็ดูเหมือนว่าการบุกรุกน้อยลง มันป้องกันการแคช แต่ฉันไม่คิดว่าการตอบสนองต่อคำขอประเภทนี้ควรถูกแคชไว้แล้ว นอกจากนี้ยังช่วยให้ผู้ใช้ API สามารถระบุวิธีการได้อย่างง่ายดายโดยไม่ต้องแยกวิเคราะห์หรือสร้าง URL ตามหลักแล้ว RESTful API อย่างแท้จริงควรให้ไฮเปอร์ลิงก์โดยไม่ต้องให้ลูกค้าสร้าง URL ด้วยตนเอง
toniedzwiedz

ถ้าคุณไม่มีคำกริยาทั้งหมดมันก็ไม่สงบเหมือนเดิมใช่ไหม?
Robert Harvey

@ RobertHarvey จริง แต่ฉันถือว่าสิ่งเหล่านี้เป็นทางเลือกไม่ใช่การออกแบบที่ตั้งใจไว้ ฉันคิดว่า API ควรสนับสนุนวิธี HTTP จริงและหากลูกค้าบางคนไม่สามารถใช้พวกเขาด้วยเหตุผลใดก็ตามพวกเขาก็สามารถแทนที่การใช้งานของพวกเขาด้วยพารามิเตอร์แบบสอบถามเหล่านี้ พร็อกซียังสามารถคว้าสิ่งเหล่านี้ได้ทันทีและแปลงคำขอเป็นคำขอโดยใช้คำกริยา HTTP ของแท้เพื่อให้เซิร์ฟเวอร์ไม่จำเป็นต้องสนใจ มี API เพียงไม่กี่ RESTful ที่แท้จริง เมื่อพูดถึง API เว็บทั่วไปมันเป็นเรื่องของรสนิยมจริงๆ โดยส่วนตัวฉันจะไปเพื่อทำความสะอาด URL ง่ายต่อการเข้าใจ IMHO
toniedzwiedz

1
@RobertHarvey ตามที่อธิบายไว้มันไม่ค่อยมีวิธีที่จะใช้พวกมัน ฉันเพิ่งพบสิ่งนี้น้อยกว่าสองสิ่งที่ชั่วร้ายเมื่อคุณต้องเอาชนะข้อ จำกัด ของลูกค้า ฉันจำการอ่านเอกสารสำหรับ API ดังกล่าวได้ แต่ฉันต้องทำการขุดในประวัติเบราว์เซอร์ / บุ๊กมาร์กเพื่อค้นหา ตอนนี้ฉันคิดแล้วส่วนหัวอาจดีกว่าในกรณีนี้ คุณเห็นด้วยไหม
toniedzwiedz

14

อันแรก

URI / URL เป็นตัวระบุทรัพยากร (คำใบ้ในชื่อ: ตัวระบุทรัพยากรแบบเดียวกัน) ด้วยการประชุมครั้งแรกทรัพยากรที่ถูกพูดถึงเมื่อคุณทำ "GET / user / 123" และทรัพยากรที่ถูกพูดถึงเมื่อคุณทำ "DELETE / user / 123" เป็นทรัพยากรเดียวกันอย่างชัดเจนเพราะพวกเขามี URL เดียวกัน

ด้วยระเบียบวิธีที่สองคุณไม่สามารถมั่นใจได้ว่า "GET / user / 123" และ "DELETE / user / delete / 123" เป็นทรัพยากรเดียวกันและดูเหมือนว่าคุณกำลังลบทรัพยากรที่เกี่ยวข้องมากกว่าทรัพยากร ตัวเองจึงจะค่อนข้างน่าแปลกใจว่าการลบจริงลบ/user/delete/123 /user/123หากคุณมีทุกการทำงานที่ทำงานบน URL ที่แตกต่างกัน URI จะไม่ทำงานเป็นตัวระบุทรัพยากรอีกต่อไป

เมื่อคุณพูดDELETE /user/123คุณกำลังพูดว่า "ลบ" บันทึกผู้ใช้ด้วยรหัส 123 '" ในขณะที่ถ้าคุณพูดDELETE /user/delete/123สิ่งที่คุณดูเหมือนจะหมายถึงคือ "ลบ" บันทึกลบผู้ใช้ที่มี ID 123 '"ซึ่งอาจไม่ใช่สิ่งที่คุณต้องการจะพูด และแม้ว่าคุณจะใช้คำกริยาที่ถูกต้องมากขึ้นในสถานการณ์นี้: "POST / ผู้ใช้ / ลบ / 123" ซึ่งระบุว่า "ทำการดำเนินการที่แนบกับ 'user deletor ด้วย id 123'" มันยังคงเป็นวงเวียนที่จะพูดว่าลบบันทึก (นี่คล้ายกับคำนามคำกริยาในภาษาอังกฤษ)

วิธีหนึ่งที่คุณสามารถนึกถึง URL ก็คือปฏิบัติต่อมันเหมือนตัวชี้ไปยังวัตถุและทรัพยากรเป็นวัตถุในการเขียนโปรแกรมเชิงวัตถุ เมื่อคุณทำGET /user/123, DELETE /user/123คุณสามารถคิดคิดว่าพวกเขาเป็นวิธีการในวัตถุ: [/user/123].get(), [/user/123].delete()ที่[]เป็นเหมือนตัวชี้ dereferencing ผู้ประกอบการ แต่สำหรับ URL (ถ้าคุณรู้ภาษาที่มีตัวชี้) หนึ่งในหลักการพื้นฐานของ REST คืออินเตอร์เฟสแบบอินเทอร์เฟซคือมีชุดคำกริยา / วิธีการที่ จำกัด และใช้ได้กับทุกสิ่งในเครือข่ายทรัพยากร / วัตถุขนาดใหญ่

ดังนั้นอันแรกดีกว่า

PS: แน่นอนว่านี่คือการดู REST ในลักษณะที่บริสุทธิ์ที่สุด ในบางครั้งการปฏิบัติจริงจะต้องมีความบริสุทธิ์และคุณต้องทำสัมปทานให้กับลูกค้าหรือโครงงานที่ทำให้สมองส่วนที่เหลือยาก


+1 สำหรับตัวอย่าง OOP :)
53777A

6

(ขออภัยครั้งแรกของฉันผ่านฉันพลาด / แก้ไข / และ / ลบ / ใน (2) ... )

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

นั่นคือคุณควรคิดถึง URIs ในแบบเดียวกับที่คุณคิดเกี่ยวกับคีย์หลักของแถวในฐานข้อมูล ระบุสิ่งที่ไม่ซ้ำกัน: Universal Resource Identifier

ดังนั้นไม่ว่าคุณจะใช้พหูพจน์หรือเอกพจน์ URI ควรเป็นตัวระบุแทนการเรียกใช้ สิ่งที่คุณพยายามจะทำในวิธีการคือ: GET (รับ), PUT (สร้าง / อัปเดต), DELETE (ลบ) หรือ POST (ทุกอย่าง)

ดังนั้น "/ item / delete / 123" จึงหยุดพัก REST เพราะมันไม่ได้ชี้ไปที่ทรัพยากรมันเป็นการเรียกใช้เมธอดมากกว่า

(นอกจากนี้เพียงแค่ความหมายคุณควรจะได้รับ URI ตัดสินใจว่ามันล้าสมัยแล้วลบURI เดียวกัน - เพราะมันเป็นตัวระบุหาก GET URI ไม่มี "/ ลบ /" และลบ จากนั้นขัดแย้งกับ HTTP semantics คุณกำลังออกอากาศ 2 หรือมากกว่า URIs ต่อทรัพยากรโดยที่ 1 จะทำ)

ตอนนี้การโกงคือ: ไม่มีคำจำกัดความที่ชัดเจนว่าอะไรคืออะไรและไม่ใช่ทรัพยากรดังนั้นการหลบหลีกใน REST ก็คือการกำหนด "คำนามการประมวลผล" และชี้ URI ไปที่นั้น นั่นเป็นเกมคำศัพท์ที่ค่อนข้างมาก แต่มันตอบสนองความหมายได้ดี

ตัวอย่างเช่นถ้าคุณไม่สามารถใช้สิ่งนี้ด้วยเหตุผลบางอย่าง:

DELETE /items/123

คุณสามารถประกาศให้โลกรู้ว่าคุณมีทรัพยากรการดำเนินการ "ลบ" และการใช้งาน

POST /items/deletor  { id: 123 }

ตอนนี้มันดูเหมือน RPC (การเรียกขั้นตอนระยะไกล) มาก แต่มันก็ผ่านช่องโหว่อันกว้างใหญ่ของส่วนคำสั่ง "การประมวลผลข้อมูล" ของ POST ของข้อกำหนดในการตั้งชื่อ HTTP spec

อย่างไรก็ตามการทำเช่นนั้นถือว่ายอดเยี่ยมมากและถ้าคุณสามารถใช้ PUT ทั่วไปสำหรับการสร้าง / อัปเดต DELETE สำหรับการลบและ POST สำหรับการผนวกสร้างและอื่น ๆ คุณควรจะใช้เพราะมันเป็น HTTP ที่ใช้มาตรฐานมากกว่า แต่ถ้าคุณมีกรณีที่มีเล่ห์เหลี่ยมเช่น "ส่งมอบ" หรือ "เผยแพร่" หรือ "ทำซ้ำ" ดังนั้นกรณีที่ใช้คำนามของหน่วยประมวลผลจะเป็นไปตามที่ REST purists และยังคงให้ความหมายที่คุณต้องการ

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