เมื่อใดที่ฉันใช้พา ธ พารามิเตอร์เทียบกับพารามิเตอร์คิวรีใน RESTful API


142

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

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


1
มีคำตอบสำหรับคำถามที่คล้ายกันที่นี่ ... stackoverflow.com/questions/3198492/…
Lalit Mehra

คำตอบ:


246

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

นี่คือตัวอย่าง สมมติว่าคุณกำลังใช้ปลายทาง RESTful API สำหรับเอนทิตีที่เรียกว่า Car คุณจะจัดโครงสร้างจุดสิ้นสุดของคุณดังนี้:

GET /cars
GET /cars/:id
POST /cars
PUT /cars/:id
ลบ/cars/:id

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

ตอนนี้สมมติว่าคุณต้องการเพิ่มความสามารถในการกรองรถยนต์ตามสีในคำขอ GET ของคุณ เนื่องจากสีไม่ใช่ทรัพยากร (เป็นคุณสมบัติของทรัพยากร) คุณสามารถเพิ่มพารามิเตอร์การสืบค้นที่ทำสิ่งนี้ได้ คุณจะเพิ่มพารามิเตอร์การสืบค้นนั้นในคำขอGET/carsของคุณดังนี้:

GET /cars?color=blue

จุดสิ้นสุดนี้จะถูกนำมาใช้เพื่อให้ส่งคืนเฉพาะรถยนต์สีน้ำเงินเท่านั้น

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

อดีต /two-words


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

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

3
แล้ว / cars? id = 1 & color = blue แทนรถยนต์ / 1 /? color = blue โดยพื้นฐานแล้วคุณกำลังกรองทรัพยากรรถยนต์ในแต่ละสถานการณ์
mko

1
ผิดตั้งแต่รถที่มี id 1 มีอยู่คันเดียว แต่รถที่มีสีน้ำเงินอาจมีหลายคัน มีความแตกต่างระหว่างตัวตนและตัวกรอง
พอล

1
สมมติฐานของฉันที่ว่าทำไมการใช้พา ธ พา ธ จึงแพร่หลายมากเป็นเพราะนักพัฒนาหลายคนได้เรียนรู้จากเฟรมเวิร์กที่ออกแบบโดยผู้ที่ไม่เข้าใจหลักการ REST ที่ดี (โดยเฉพาะ Ruby on Rails)
Chris Broski

58

วิธีคิดพื้นฐานเกี่ยวกับเรื่องนี้มีดังนี้:

URI คือตัวระบุทรัพยากรที่ระบุอินสแตนซ์เฉพาะของ TYPE ของทรัพยากรโดยไม่ซ้ำกัน เช่นเดียวกับสิ่งอื่น ๆ ในชีวิตวัตถุทุกชิ้น (ซึ่งเป็นตัวอย่างของบางประเภท) มีชุดแอตทริบิวต์ที่ไม่แปรผันตามเวลาหรือชั่วคราว

ในตัวอย่างข้างต้นรถยนต์เป็นวัตถุที่จับต้องได้มากซึ่งมีคุณลักษณะเช่นยี่ห้อรุ่นและ VIN ซึ่งไม่เคยเปลี่ยนแปลงและสีระบบกันสะเทือน ฯลฯ ที่อาจเปลี่ยนแปลงไปตามกาลเวลา ดังนั้นหากเราเข้ารหัส URI ด้วยแอตทริบิวต์ที่อาจเปลี่ยนแปลงเมื่อเวลาผ่านไป (ชั่วขณะ) เราอาจจบลงด้วย URI หลายรายการสำหรับวัตถุเดียวกัน:

GET /cars/honda/civic/coupe/{vin}/{color=red}

และหลายปีต่อมาหากสีของรถคันเดียวกันนี้เปลี่ยนเป็นสีดำ:

GET /cars/honda/civic/coupe/{vin}/{color=black}

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

ดังนั้น URI ควรประกอบด้วยเฉพาะส่วนที่ไม่มีวันเปลี่ยนแปลงและจะระบุทรัพยากรนั้นโดยไม่ซ้ำกันตลอดอายุการใช้งาน ทุกสิ่งที่อาจเปลี่ยนแปลงควรสงวนไว้สำหรับพารามิเตอร์การค้นหาเช่น:

GET /cars/honda/civic/coupe/{vin}?color={black}

บรรทัดล่าง - คิดว่าพหุสัณฐาน


2
กระบวนทัศน์ที่น่าสนใจ .. นี่คือแพตเทนการออกแบบที่ใช้กันทั่วไป คุณสามารถจัดหา API บางส่วนที่ใช้สิ่งนี้ในเอกสารประกอบหรือข้อมูลอ้างอิงบางส่วนที่สรุปกลยุทธ์นี้ได้หรือไม่
cosbor11

1
ฉันชอบวิธีที่คุณเน้น "TYPE" เมื่อคุณเขียนว่า "A URI คือตัวระบุทรัพยากรที่ระบุอินสแตนซ์เฉพาะของ TYPE ของทรัพยากร" ฉันคิดว่านั่นเป็นความแตกต่างที่สำคัญ
jrahhali

15

ใน REST API คุณไม่ควรกังวลมากเกินไปกับ URI ที่คาดเดาได้ ข้อเสนอแนะเกี่ยวกับความสามารถในการคาดเดา URI นั้นบ่งบอกถึงความเข้าใจผิดเกี่ยวกับสถาปัตยกรรม RESTful สมมติว่าลูกค้าควรสร้าง URI ขึ้นมาเองซึ่งพวกเขาไม่ควรต้องทำ

อย่างไรก็ตามฉันคิดว่าคุณไม่ได้สร้าง REST API จริง แต่เป็น API 'REST inspired' (เช่น Google Drive one) ในกรณีเหล่านี้หลักทั่วไปคือ 'path params = resource identification' และ 'query params = resource sorting' ดังนั้นคำถามก็คือคุณสามารถระบุทรัพยากรของคุณโดยไม่ซ้ำกันโดยไม่มีสถานะ / ภูมิภาคได้หรือไม่? ถ้าใช่อาจเป็นพารามิเตอร์การค้นหา ถ้าไม่มีแสดงว่าเป็นพารามิเตอร์พา ธ

HTH


12
ฉันไม่เห็นด้วย API ที่ดีควรคาดเดาได้ สงบหรืออย่างอื่น
cosbor11

3
ฉันคิดอย่างนั้น ควรมีความคล้องจองและเหตุผลว่า URI ถูกสร้างขึ้นอย่างไรแทนที่จะตั้งชื่อจุดสิ้นสุดโดยพลการ เมื่อเราสามารถเขียนไคลเอนต์ API ได้โดยไม่ต้องอ้างอิงเอกสารอย่างต่อเนื่องแสดงว่าคุณได้เขียน API ที่ดีในความคิดของฉัน
cosbor11

2
"เมื่อเราสามารถเขียนไคลเอนต์ API ได้โดยไม่ต้องอ้างอิงเอกสาร" นั่นคือสิ่งที่ฉันคิดว่าความเข้าใจของเราเกี่ยวกับ REST แตกต่างกัน ... ไคลเอนต์ API ไม่จำเป็นต้อง 'สร้าง' URL พวกเขาควรเลือกจากการตอบสนองของการเรียก API ก่อนหน้านี้ หากคุณใช้เว็บไซต์เป็นตัวเปรียบเทียบ ... คุณไปที่ facebook.com จากนั้นคุณเลือกลิงก์ไปยังหน้ากิจกรรม คุณไม่สนใจว่า URL เหตุการณ์ของ facebook จะ 'คาดเดาได้' หรือไม่เนื่องจากคุณไม่ได้พิมพ์เข้าไปคุณไปที่นั่นผ่านลิงก์ไฮเปอร์มีเดีย เช่นเดียวกับ REST api ดังนั้นทำให้ URI มีความหมายสำหรับคุณ (เซิร์ฟเวอร์) แต่ไม่ใช่ไคลเอนต์ของคุณ
Oliver McPhee

2
เพิ่มหมายเหตุ นี่ไม่ได้หมายความว่า URI ไม่ควรเป็นไปตามรูปแบบที่เข้าใจง่ายเพียง แต่หมายความว่าไม่ใช่ข้อ จำกัด ของ RESTful API ปัญหาใหญ่ที่สุดของพื้นที่นี้คือคนที่คิดว่าลูกค้าควรสร้าง URL ขึ้นมาเอง พวกเขาไม่ควรเนื่องจากสร้างการมีเพศสัมพันธ์ระหว่างไคลเอนต์และเซิร์ฟเวอร์ที่ไม่ควรมีอยู่ (เช่น - เซิร์ฟเวอร์ไม่สามารถเปลี่ยน URL ได้โดยไม่ทำลายแอปพลิเคชันไคลเอนต์ทั้งหมด) ใน REST API เซิร์ฟเวอร์สามารถเปลี่ยนแปลงได้ตามที่ต้องการ
Oliver McPhee

3
+1 สำหรับการใช้คำต่อไปนี้: "'path params = resource identification' และ 'query params = resource sorting'" สิ่งนี้ทำให้ฉันกระจ่างขึ้นจริงๆ
Doug

3

เมื่อฉันออกแบบ API ทรัพยากรหลักคือpeopleอะไร โดยปกติผู้ใช้จะขอให้กรองpeopleดังนั้นเพื่อป้องกันไม่ให้ผู้ใช้โทรหาบางอย่างเช่น/people?settlement=urbanทุกครั้งฉันจึงใช้งาน/people/urbanซึ่งทำให้ฉันสามารถเพิ่มได้ใน/people/ruralภายหลัง นอกจากนี้ยังอนุญาตให้เข้าถึง/peopleรายการทั้งหมดหากมีการใช้งานในภายหลัง ในระยะสั้นเหตุผลของฉันคือการเพิ่มเส้นทางไปยังส่วนย่อยทั่วไป

จากที่นี่ :

นามแฝงสำหรับข้อความค้นหาทั่วไป

เพื่อให้ประสบการณ์ API น่าพึงพอใจยิ่งขึ้นสำหรับผู้บริโภคทั่วไปให้พิจารณาบรรจุชุดเงื่อนไขลงในเส้นทาง RESTful ที่เข้าถึงได้ง่าย ตัวอย่างเช่นคำค้นหาตั๋วที่เพิ่งปิดไปด้านบนอาจรวมเป็นGET /tickets/recently_closed


1

โดยทั่วไปฉันมักจะใช้พารามิเตอร์เส้นทางเมื่อมี 'ลำดับชั้น' ที่ชัดเจนในทรัพยากรเช่น:

/region/state/42

หากทรัพยากรเดียวนั้นมีสถานะสามารถ:

/region/state/42/status

อย่างไรก็ตามหาก 'ภูมิภาค' ไม่ได้เป็นส่วนหนึ่งของทรัพยากรที่ถูกเปิดเผยจริงๆอาจเป็นหนึ่งในพารามิเตอร์การค้นหาซึ่งคล้ายกับการแบ่งหน้า (ตามที่คุณกล่าวถึง)


0

การแบ่งกลุ่มเป็นลำดับชั้นและ "สวย" แต่สามารถ จำกัด ได้

ตัวอย่างเช่นหากคุณมี URL ที่มีสามส่วนแต่ละส่วนจะส่งผ่านพารามิเตอร์ที่แตกต่างกันเพื่อค้นหารถยนต์ผ่านยี่ห้อรุ่นและสี:

www.example.com/search/honda/civic/blue

นี่เป็น url ที่สวยมากและผู้ใช้ปลายทางจำได้ง่ายขึ้น แต่ตอนนี้คุณติดอยู่กับโครงสร้างนี้ สมมติว่าคุณต้องการทำเพื่อให้ในการค้นหาผู้ใช้สามารถค้นหารถยนต์สีน้ำเงินทั้งหมดหรือ Honda Civics ทั้งหมด? พารามิเตอร์การค้นหาแก้ปัญหานี้ได้เนื่องจากให้คู่ค่าคีย์ เพื่อให้คุณผ่าน:

www.example.com/search?color=blue
www.example.com/search?make=civic

ตอนนี้คุณมีวิธีอ้างอิงค่าผ่านทางคีย์ - ไม่ว่าจะเป็น "color" หรือ "make" ในโค้ดการสืบค้นของคุณ

คุณสามารถหลีกเลี่ยงสิ่งนี้ได้โดยอาจใช้กลุ่มเพิ่มเติมเพื่อสร้างโครงสร้างค่าคีย์เช่น:

www.example.com/search/make/honda/model/civic/color/blue

หวังว่าคงเข้าท่า ..


-2

ตัวอย่าง URL: /rest/{keyword}

URL นี้เป็นตัวอย่างสำหรับพารามิเตอร์เส้นทาง เราสามารถรับข้อมูล URL นี้ได้โดยใช้@PathParam.

ตัวอย่าง URL: /rest?keyword=java&limit=10

URL นี้เป็นตัวอย่างสำหรับพารามิเตอร์การค้นหา เราสามารถรับข้อมูล URL นี้ได้โดยใช้@Queryparam.

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