Khi nào tôi sử dụng tham số đường dẫn so với tham số truy vấn trong API RESTful?


141

Tôi muốn làm cho API RESTful của mình rất dễ đoán. Cách thực hành tốt nhất để quyết định khi nào thực hiện phân đoạn dữ liệu bằng URI thay vì sử dụng tham số truy vấn.

Nó có ý nghĩa với tôi rằng các tham số hệ thống hỗ trợ phân trang, sắp xếp và nhóm là sau '?' Nhưng còn các trường như 'trạng thái' và 'vùng' hoặc các thuộc tính khác phân đoạn bộ sưu tập của bạn thì sao? Nếu đó cũng là các tham số truy vấn, quy tắc của việc biết khi nào nên sử dụng tham số đường dẫn là gì?


1
một câu hỏi tương tự đã được trả lời ở đây ... stackoverflow.com/questions/3198492/
Khăn

Câu trả lời:


239

Thực tiễn tốt nhất cho thiết kế API RESTful là các tham số đường dẫn được sử dụng để xác định một tài nguyên hoặc tài nguyên cụ thể, trong khi các tham số truy vấn được sử dụng để sắp xếp / lọc các tài nguyên đó.

Đây là một ví dụ. Giả sử bạn đang triển khai các điểm cuối API RESTful cho một thực thể gọi là Xe hơi. Bạn sẽ cấu trúc các điểm cuối của bạn như thế này:

GET /cars
GET /cars/:id
POST /cars
PUT /cars/:id
DELETE/cars/:id

Theo cách này, bạn chỉ sử dụng các tham số đường dẫn khi bạn chỉ định tài nguyên nào cần tìm nạp, nhưng điều này không sắp xếp / lọc tài nguyên theo bất kỳ cách nào.

Bây giờ, giả sử bạn muốn thêm khả năng lọc các ô tô theo màu trong các yêu cầu GET của bạn. Vì màu sắc không phải là tài nguyên (nó là thuộc tính của tài nguyên), bạn có thể thêm một tham số truy vấn thực hiện việc này. Bạn sẽ thêm tham số truy vấn đó vào yêu cầu GET/cars của bạn như thế này:

ĐƯỢC /cars?color=blue

Điểm cuối này sẽ được thực hiện để chỉ những chiếc xe màu xanh sẽ được trả lại.

Theo như cú pháp có liên quan, tên URL của bạn phải là chữ thường. Nếu bạn có một tên thực thể thường là hai từ tiếng Anh, bạn sẽ sử dụng dấu gạch nối để phân tách các từ, không phải trường hợp lạc đà.

Ví dụ. /two-words


3
Cảm ơn bạn đã trả lời Mike. Đây là một phương pháp rõ ràng và đơn giản; đáng để bình chọn từ tôi Tuy nhiên, đôi khi, các nhà phát triển chọn cách tiếp cận 'ô tô / màu xanh', tôi tự hỏi lý do của họ là gì để làm như vậy ... có lẽ họ quyết định tạo thông số đường dẫn cho các trường bắt buộc hoặc có thể họ làm điều đó để chỉ ra rằng cơ sở dữ liệu được phân vùng bởi phân đoạn đó.
cosbor11

1
Tôi không chắc lý do của họ là gì. Thành thật mà nói, tôi không đồng ý với nó. Tôi nghĩ rằng theo các quy ước và giữ cho nó đơn giản có ý nghĩa nhất. Bằng cách đó, bạn cho phép người tiêu dùng API của bạn hiểu rõ hơn chính xác những gì họ cần làm để truy cập chức năng của nó.
Mike

3
những gì về / xe? id = 1 & color = blue thay vì ô tô / 1 /? color = blue. về cơ bản, bạn đang lọc tài nguyên ô tô trong mỗi kịch bản
mko

1
Sai vì xe có id 1 chỉ tồn tại một nhưng xe có màu xanh có lẽ nhiều. Có sự phân biệt giữa danh tính và bộ lọc
paul

1
Giả thuyết của tôi về lý do tại sao sử dụng thông số đường dẫn lại phổ biến đến vậy là do nhiều nhà phát triển đã học được từ các khung được thiết kế bởi những người không nắm vững các nguyên tắc REST (đặc biệt là Ruby on Rails.)
Chris Broski

58

Cách cơ bản để suy nghĩ về chủ đề này như sau:

URI là một mã định danh tài nguyên xác định duy nhất một thể hiện cụ thể của TYPE tài nguyên. Giống như mọi thứ khác trong cuộc sống, mọi đối tượng (là một thể hiện của một số loại), có tập hợp các thuộc tính là bất biến theo thời gian hoặc tạm thời.

Trong ví dụ trên, một chiếc xe hơi là một vật thể rất hữu hình có các thuộc tính như make, model và VIN - không bao giờ thay đổi, và màu sắc, hệ thống treo, vv có thể thay đổi theo thời gian. Vì vậy, nếu chúng ta mã hóa URI bằng các thuộc tính có thể thay đổi theo thời gian (tạm thời), chúng ta có thể kết thúc với nhiều URI cho cùng một đối tượng:

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

Và nhiều năm sau, nếu màu của chiếc xe này giống nhau được đổi thành màu đen:

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

Lưu ý rằng bản thân ô tô (đối tượng) không thay đổi - đó chỉ là màu thay đổi. Có nhiều URI trỏ đến cùng một đối tượng sẽ buộc bạn phải tạo nhiều trình xử lý URI - đây không phải là một thiết kế hiệu quả và tất nhiên là không trực quan.

Do đó, URI chỉ nên bao gồm các phần sẽ không bao giờ thay đổi và sẽ tiếp tục xác định duy nhất tài nguyên đó trong suốt vòng đời của nó. Mọi thứ có thể thay đổi nên được dành riêng cho các tham số truy vấn, như vậy:

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

Dòng dưới cùng - nghĩ đa hình.


2
Mô hình thú vị .. Đây có phải là một thiết kế thường được sử dụng? Bạn có thể cung cấp một số API sử dụng điều này trong tài liệu của họ hoặc một số tài liệu tham khảo phác thảo chiến lược này không?
cosbor11

1
Tôi thích cách bạn nhấn mạnh "TYPE" khi bạn viết "URI là một mã định danh tài nguyên xác định duy nhất một thể hiện cụ thể của TYPE tài nguyên". Tôi nghĩ đó là một sự khác biệt quan trọng.
jrahhali

15

Trong API REST, bạn không nên quá lo lắng bởi các URI có thể dự đoán được. Rất gợi ý về khả năng dự đoán URI ám chỉ sự hiểu lầm về kiến ​​trúc RESTful. Nó giả định rằng một khách hàng nên tự xây dựng các URI mà họ thực sự không cần phải làm.

Tuy nhiên, tôi cho rằng bạn không tạo API REST thực sự mà là API 'lấy cảm hứng từ REST' (chẳng hạn như Google Drive). Trong những trường hợp này, quy tắc của ngón tay cái là 'đường dẫn params = nhận dạng tài nguyên' và 'truy vấn params = sắp xếp tài nguyên'. Vì vậy, câu hỏi trở thành, bạn có thể xác định duy nhất tài nguyên của mình mà KHÔNG CÓ trạng thái / khu vực không? Nếu có, thì có lẽ đó là một truy vấn param. Nếu không, thì đó là một thông số đường dẫn.

HTH.


11
Tôi không đồng ý, một API tốt nên được dự đoán trước; RESTful hoặc cách khác.
cosbor11

3
Tôi nghĩ vậy. Cần có vần điệu và lý do về cách URI được hình thành, thay vì đặt tên các điểm cuối một cách tùy tiện. Khi một người có thể viết một ứng dụng API một cách trực quan mà không cần liên tục tham khảo tài liệu, theo ý kiến ​​của tôi, bạn đã viết một API tốt.
cosbor11

2
"Khi một người có thể viết một ứng dụng API một cách trực quan mà không cần liên tục tham khảo tài liệu". Đó là nơi tôi nghĩ rằng sự hiểu biết của chúng tôi về REST khác nhau ... ứng dụng khách API không bao giờ cần phải 'xây dựng' một URL. Họ nên chọn nó từ phản hồi của lệnh gọi API trước đó. Nếu bạn lấy một trang web tương tự ... Bạn truy cập facebook.com, sau đó bạn chọn một liên kết đến trang sự kiện. Bạn không quan tâm liệu URL sự kiện trên facebook có phải là 'có thể dự đoán được' hay không, khi bạn không nhập nó vào. Bạn đến đó thông qua các liên kết hypermedia. Điều tương tự cũng đúng với api REST. Vì vậy, hãy làm cho các URI có ý nghĩa với bạn (máy chủ), nhưng không phải là ứng dụng khách thứ hai
Oliver McPhee

2
Đã thêm ghi chú. Điều này không có nghĩa là các URI không nên theo một mẫu dễ hiểu, nó chỉ có nghĩa là nó không phải là một ràng buộc của API RESTful. Vấn đề lớn nhất với khu vực này là mọi người cho rằng khách hàng nên tự xây dựng các URL. Họ không nên, vì điều đó tạo ra một khớp nối giữa máy khách và máy chủ không nên tồn tại. (ví dụ: máy chủ không thể thay đổi URL mà không phá vỡ tất cả các ứng dụng khách). Trong API REST, máy chủ có thể thay đổi chúng khi nó vừa ý.
Oliver McPhee

3
+1 để sử dụng các từ sau: "'path params = resource id' và 'query params = resource sorting'". Điều này thực sự xóa nó cho tôi.
Doug

3

Khi tôi đã thiết kế một API mà tài nguyên chính là people. Thông thường người dùng sẽ yêu cầu được lọc peoplenhư vậy, để ngăn người dùng gọi một cái gì đó như /people?settlement=urbanmọi lần, tôi đã triển khai /people/urbanđể sau này cho phép tôi dễ dàng thêm /people/rural. Ngoài ra, điều này cho phép truy cập vào /peopledanh sách đầy đủ nếu nó sẽ được sử dụng sau này. Nói tóm lại, lý luận của tôi là thêm một đường dẫn đến các tập con chung

Từ đây :

Bí danh cho các truy vấn phổ biến

Để làm cho trải nghiệm API trở nên dễ chịu hơn đối với người tiêu dùng trung bình, hãy xem xét việc đóng gói các bộ điều kiện vào các đường dẫn RESTful có thể truy cập dễ dàng. Ví dụ: truy vấn vé đã đóng gần đây ở trên có thể được đóng gói thànhGET /tickets/recently_closed


1

Nói chung, tôi có xu hướng sử dụng các tham số đường dẫn khi có một 'thứ bậc' rõ ràng trong tài nguyên, chẳng hạn như:

/region/state/42

Nếu tài nguyên đơn lẻ đó có trạng thái, người ta có thể:

/region/state/42/status

Tuy nhiên, nếu 'vùng' không thực sự là một phần của tài nguyên bị lộ, thì nó có thể thuộc một trong các tham số truy vấn - tương tự như phân trang (như bạn đã đề cập).


0

Phân khúc có nhiều thứ bậc và "đẹp" nhưng có thể hạn chế.

Ví dụ: nếu bạn có một url có ba phân đoạn, mỗi phân đoạn sẽ chuyển các tham số khác nhau để tìm kiếm một chiếc xe thông qua nhãn hiệu, kiểu dáng và màu sắc:

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

Đây là một url rất đẹp và dễ nhớ hơn bởi người dùng cuối, nhưng bây giờ loại của bạn bị mắc kẹt với cấu trúc này. Giả sử bạn muốn thực hiện để trong tìm kiếm, người dùng có thể tìm kiếm TẤT CẢ những chiếc xe màu xanh hoặc TẤT CẢ Honda Công dân? Một tham số truy vấn giải quyết điều này bởi vì nó đưa ra một cặp giá trị khóa. Vì vậy, bạn có thể vượt qua:

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

Bây giờ bạn có một cách để tham chiếu giá trị thông qua khóa đó - "màu" hoặc "tạo" trong mã truy vấn của bạn.

Bạn có thể khắc phục điều này bằng cách có thể sử dụng nhiều phân khúc hơn để tạo một loại cấu trúc giá trị chính như:

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

Hy vọng rằng có ý nghĩa ..


-2

URL ví dụ: /rest/{keyword}

URL này là một ví dụ cho các tham số đường dẫn. Chúng tôi có thể lấy dữ liệu URL này bằng cách sử dụng @PathParam.

URL ví dụ: /rest?keyword=java&limit=10

URL này là một ví dụ cho các tham số truy vấn. Chúng tôi có thể lấy dữ liệu URL này bằng cách sử dụng @Queryparam.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.