แสดงการกระทำ (คำกริยา) ใน REST URI


16

ฉันมีการพิมพ์เพื่อดำเนินการกับเอกสารลูกค้าของฉัน ฉันต้องการการดำเนินการมาตรฐานอื่น ๆ ที่จะดำเนินการเช่นกันเช่นเพิ่มอัปเดตลบ ดังนั้นฉันมีดังต่อไปนี้:

  • สำหรับการสร้างลูกค้าใหม่:
    URI = / customer / {id} ให้พิมพ์ = POST, Methodname = CreateCustomer ()
  • สำหรับการอัพเดต:
    URI: / customer / {id} ให้พิมพ์ = PUT, method = UpdateCstomer ()
  • สำหรับลบลูกค้า:
    URI = / customer / {id} ให้พิมพ์ = DELETE, Methodname = DeleteCustomer ()
  • สำหรับมุมมอง:
    URI: / customer / {id} ให้พิมพ์ = GET, method = GetCustomer ()

ตอนนี้ถ้าฉันต้องการพิมพ์เอกสารสำหรับลูกค้ารายนั้นฉันต้องการฟังก์ชั่นการพิมพ์ URI ของฉันอาจมีลักษณะเช่นนี้: / customer / {id}, type = POST, method = PrintCustomer () แต่ฉันได้ใช้ประเภท URI และ POST นั้นสำหรับ CreateCustomer ฉันต้องการให้ URI มีลักษณะดังนี้: / customer / Print / {id}, type = POST, method = PrintCustomer ()

แต่ฉันไม่สามารถมีคำกริยา "พิมพ์" ใน URI ของฉัน วิธีที่ดีที่สุดในการทำเช่นนี้คืออะไร? ฉันคิดถึง / customer / document / {id} เป็น URI ... แต่ฉันจะพบปัญหาเดียวกัน ฉันจะมีการดำเนินการ CRUD ใน "เอกสาร" ดังนั้นฉันหมดสิ่งที่ฉันจะใช้สำหรับ "พิมพ์" อีกครั้ง กรุณาแนะนำ


2
การพิมพ์มักจะเป็นการดำเนินการด้านไคลเอนต์ดังนั้นฉันอยากรู้ว่าการตั้งค่าของคุณนั้นต้องการให้คุณส่งคำสั่งไปยังเซิร์ฟเวอร์ REST อย่างไร
Shauna

2
@Shauna ไม่จำเป็น URI อาจเป็นคำขอไปยังเซิร์ฟเวอร์เพื่อขอทรัพยากรรุ่นที่เหมาะกับการพิมพ์ (เช่นมุมมองที่ต่างออกไป)
Evan Plaice

1
@EvanPlaice - ยุติธรรมเพียงพอ แต่ที่ยังคงออกจากการกระทำในการพิมพ์ให้กับลูกค้า (ซึ่งแม้หลังจากการเรียกรุ่นพิมพ์ง่ายฝั่งเซิร์ฟเวอร์จากนั้นก็จะตัดสินใจเลือกสิ่งที่อุปกรณ์ในการพิมพ์และส่งคำสั่งพิมพ์เองแม้ที่ คำสั่งไปที่เซิร์ฟเวอร์การพิมพ์) การร้องขอให้รับทรัพยากรที่เป็นมิตรกับรุ่นที่พิมพ์ได้นั้นก็คือ ... ดี ... GET
Shauna

@Shauna การเรียกใช้งานพิมพ์จากคำขอ HTTP เพียงอย่างเดียวนั้นเป็นไปไม่ได้เนื่องจากความปลอดภัยของเบราว์เซอร์ การร้องขอสำหรับเวอร์ชันที่เหมาะสำหรับการพิมพ์นั้นเป็นเพียงการร้องขอ GET แต่คุณยังคงต้องการวิธีระบุว่าเบราว์เซอร์ควรแสดงเวอร์ชันที่พิมพ์ได้ คุณสามารถระบุ URL ที่แตกต่างกันได้ แต่นั่นจะเป็นการละเมิดหลักการของ REST เพราะคุณไม่ได้ร้องขอทรัพยากรที่แตกต่างกันเพียงแค่เปลี่ยนทรัพยากรที่เหมือนกันเท่านั้น ดังนั้นเหตุผลในการระบุการแปลงผ่านการสืบค้นพารามิเตอร์และ / หรือเนื้อหาประเภท
Evan Plaice

ฉันไม่มีตัวแทนมากพอที่จะโพสต์เป็นคำตอบ แต่ฉันคิดว่ามันน่าสนใจที่tyk.io/rest-never-crudโต้แย้งว่านั่นPOST /customers/123/printเป็นสิ่งที่ถูกต้อง
jlh

คำตอบ:


9

POSTไม่ได้หมายถึง "สร้าง" แต่หมายถึง "กระบวนการ" คุณสามารถสร้างทรัพยากรใหม่ได้โดยการโพสต์คำขอที่เหมาะสมไปยังทรัพยากรที่มีอยู่ (เช่นโพสต์/customersเพื่อสร้างลูกค้าใหม่) แต่คุณสามารถใช้POSTเพื่อเติมเต็มการกระทำอื่น ๆ ทั้งหมดที่ไม่สอดคล้องกับกระบวนทัศน์ CRUD ที่เรียบร้อย

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

ในฐานะที่เป็นเอกสาร JSON อาจมีลักษณะเช่นนี้:

{
   contents: ["http://site/customers/12345"],
   paper-size: "A4",
   duplex: "true"
}

เห็นได้ชัดว่าคุณต้องกำหนดค่านี้ให้เกี่ยวข้องกับสิ่งที่คุณต้องการทำ สิ่งสำคัญคือคุณระบุทรัพยากรอื่น ๆ ที่จะพิมพ์โดยระบุ URL ของพวกเขา

ในการตอบสนองต่อการร้องขอคุณสามารถส่งคืน200 OKหรือ204 No-Contentปฏิบัติและปฏิบัติตามขั้นตอนและลืมได้ แต่ถ้าคุณต้องการที่จะเพิ่มความมันคุณจะกลับมา201 Createdและระบุ URL /prints/12345ของงานพิมพ์ที่สร้างขึ้นใหม่เช่น

จากนั้นผู้ใช้สามารถดำเนินการGETบนทรัพยากรเพื่อดูสถานะของงานพิมพ์ของพวกเขา (อยู่ระหว่างดำเนินการในความคืบหน้า ฯลฯ ) DELETEหรือสามารถของานถูกยกเลิกโดยการออก

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


2
โพสต์มักจะหมายถึงการสร้าง / แทรกในขณะที่ใส่มักจะหมายถึงการปรับปรุงบันทึก / ปรับปรุง นั่นคือวิธีที่กำหนดไว้ใน REST แม้ว่าจะไม่ใช่วิธีที่ใช้ใน HTML
Evan Plaice

2
@EvanPlaice ข้อมูลจำเพาะ HTTP ชื่อ PUT เป็นคำกริยาสร้าง / อัปเดต (ใช้รูปแบบการสร้าง + ปรับปรุงแทนการสร้าง + เรียกคืน + อัปเดตที่คุ้นเคยมากขึ้นและ POST เป็นคำกริยา "การประมวลผลข้อมูล" เช่นเดียวกับกริยา "ผนวก" . Roy Fielding ในบล็อกของเขาอธิบายว่า POST เป็นคำกริยาที่ใช้เมื่อคุณไม่ต้องการสร้างมาตรฐานการทำงาน POST จะใช้เวลาในการ "สร้าง" ความหมายเมื่อคุณพิจารณาว่าจะผนวกรายการใหม่เข้ากับคอลเลกชันของรายการ ในกรณีนี้ผู้โศกนาฏกรรมตีตะปูบนหัวโดยใช้ POST สำหรับการประมวลผลหรือเพิ่มงานพิมพ์
Rob

@RobY ตกลงที่เหมาะสม ตัวอย่างสามารถใช้ PUT เพื่อแสดง SPROC ที่ออกแบบมาเพื่อป้อนข้อมูลลงในฐานข้อมูล ในขณะที่ POST สามารถทำขั้นตอนกลางและการกลายพันธุ์ที่จำเป็นในการรวบรวม / เตรียมข้อมูลนั้น การออกแบบของการดำเนินการ POST สามารถเปลี่ยนแปลงหรือแทนที่ได้ในขณะที่การออกแบบวิวัฒนาการ แต่การดำเนินการ PUT แสดงถึงรูปแบบที่ไม่ควรเปลี่ยน ฉันจะปรับปรุงคำตอบของฉัน แต่อันนี้ทำหน้าที่ได้ดีในการอธิบายความแตกต่าง
Evan Plaice

4

ฉันทำสิ่งนี้มาก่อน ในการพิมพ์เอกสารฉันแค่ส่งคืนทรัพยากรในรูปแบบ pdf ลูกค้าจะต้องส่งคำขอ GET สำหรับทรัพยากรด้วยแอปพลิเคชันส่วนหัวยอมรับ / pdf

สิ่งนี้ยังหลีกเลี่ยงการสร้าง URI ใหม่สำหรับทรัพยากรชั่วคราวเช่นงานพิมพ์ การใช้ส่วนหัว HTTP เป็นส่วนหนึ่งของ REST และช่วยให้ URI สะอาด


3

เพียงเพิ่มพารามิเตอร์ใน GET ของ URI ปัจจุบัน

เป็นเรื่องปกติที่จะใช้ URI เพื่อดำเนินการหลายอย่าง

หากคุณกำลังพูดถึงทรัพยากรเดียวกัน แต่เป็นการกระทำที่แตกต่างคุณจะต้องกำหนดเป็นพารามิเตอร์

/ ลูกค้า / {ID}? พิมพ์ = true

จากนั้นที่ที่คุณกำหนดวิธีการ GET ของคุณคุณจะตรวจพบว่ามีพารามิเตอร์การพิมพ์และจัดการกับมันแตกต่างกันอย่างไร

REST ถูกกำหนดด้วยวิธีต่อไปนี้:

  • POST - สร้างระเบียนสินทรัพย์หรือทรัพยากร
  • PUT - อัปเดตระเบียนสินทรัพย์หรือทรัพยากร
  • DELETE - ลบ, บันทึก, สินทรัพย์หรือทรัพยากร

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

ข้อมูลจำเพาะของ REST นั้นค่อนข้างคาดคิดมาก่อนแม้ว่า API นั้นเพิ่งจะเริ่มใช้งานอย่างหนัก

หากคุณสนใจที่จะเรียนรู้เพิ่มเติมเกี่ยวกับโปรโตคอล REST ฉันขอแนะนำให้คุณอ่าน " Haters Gonna Hate HATEOAS "


ปรับปรุง:

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

ตัวอย่างเช่นคุณสามารถแสดง URI เป็น:

/customer/{id}+print

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

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

// for application/json
/customer/{id}+json

// for application/atom+xml
/customer/{id}+atom

ทั้งสองวิธีทุกรูปแบบเป็นที่ยอมรับ การติดตั้งที่คุณตัดสินใจนั้นขึ้นอยู่กับความชอบส่วนบุคคลและความสามารถของเซิร์ฟเวอร์ของคุณ

นอกเหนือจากนี้ให้ฉันอธิบายเพราะดูเหมือนจะมีความสับสน 'คิวรี' พารามิเตอร์แบบสอบถามและ / หรือเนื้อหาชนิดถูกใช้เพื่อระบุวิธีการแปลงทรัพยากร ไม่ใช่วิธีเรียกใช้งานพิมพ์จริง เพื่อเหตุผลด้านความปลอดภัยการเข้าถึงระดับฮาร์ดแวร์จะถูกปล่อยไปยังผู้ใช้ / ลูกค้า / เบราว์เซอร์เสมอ


หากต้องการเพิ่ม - เป็นอีกทางเลือกหนึ่งในการใช้สตริงการสืบค้น ( ?print=true) คุณสามารถใช้พารามิเตอร์ URI (เช่น - /customer/{id}/printable) สิ่งที่คุณใช้ส่วนใหญ่จะขึ้นอยู่กับมาตรฐานของระบบ (CMS, กรอบงาน, รหัสทั่วไป) ที่ตั้งค่าให้จัดการ ทั้งสองจะถือว่าถูกต้องและเป็นที่ยอมรับ
Shauna

@Shauna ในทางเทคนิควิธีที่ดีที่สุดคือการใช้ MIME เฉพาะประเภทในการพิมพ์ด้วย URI '/ customer / {id} + print' และการตอบกลับ MIME-Type ของข้อความ / html + print ข้อดีของวิธีการดังกล่าวคือคุณสามารถสร้างการแปลงสำหรับประเภท MIME จำนวนมาก (เช่น text / html, text / x-markdown, application / json, ฯลฯ ) สำหรับ URI เดียวกัน ข้อเสียของโซลูชันที่คุณนำเสนอคือคุณจะต้องสร้าง URI เพิ่มเติม (และกำหนดเส้นทางอื่น) สำหรับประเภท MIME ทุกประเภท มันแพ้จุดประสงค์ของการใช้ REST
Evan Plaice

(ต่อ) ฉันจะยืนยันว่า URI-hacks เป็นรูปแบบการต่อต้านที่ได้รับการแนะนำโดยชุมชน ROR เป็นหลัก แต่นั่นไม่ได้หมายความว่าพวกเขาไม่มีประโยชน์ ด้วยการมาถึงของเซิร์ฟเวอร์ HTTPd ระดับต่ำที่ดีกว่ามันง่ายกว่าที่จะใช้งาน REST ในลักษณะที่ใช้ประโยชน์จากศักยภาพทั้งหมดอย่างเต็มที่ สิ่งต่าง ๆ มาไกลตั้งแต่วันที่ Apache และการกำหนดเส้นทางทุกอย่างผ่าน index.html เป็นตัวเลือกเดียว
Evan Plaice

2
GET ไม่ควรทำการเปลี่ยนแปลงสถานะหรือมีผลข้างเคียง พิจารณาว่า GET เป็น idempotent ซึ่งหมายความว่ามิดเดิลแวร์อาจลองใหม่อีกครั้งหากไม่เห็นว่าผ่านไป ในกรณีนี้การลองใหม่แต่ละครั้งจะส่งผลให้สำเนาเอกสารใหม่ที่พิมพ์ใหม่ ;)
Rob

@ Roby ฉันคิดว่าการกระทำ 'print' จะไม่จัดการกับกระบวนการพิมพ์เอกสารเพราะเบราว์เซอร์และไดรเวอร์การพิมพ์จะทำงานได้ดีขึ้น แต่ผลลัพธ์ของสื่อ / การพิมพ์จะคืนค่าการแสดงเอกสาร 'เป็นมิตรกับการพิมพ์' ดังนั้น idempotency จึงยังคงอยู่ ข้อดีก็คือการส่งงานพิมพ์ผ่านอินเทอร์เน็ตอย่างไร้สัญชาติน่าจะเป็นช่วงเวลาที่เลวร้าย
Evan Plaice
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.