Làm thế nào để tìm kiếm phù hợp với giao diện RESTful?


137

Khi thiết kế giao diện RESTful, ngữ nghĩa của các loại yêu cầu được coi là quan trọng đối với thiết kế.

  • NHẬN - Thu thập danh sách hoặc lấy phần tử
  • PUT - Thay thế bộ sưu tập hoặc phần tử
  • POST - Tạo bộ sưu tập hoặc phần tử
  • XÓA - Vâng, erm, xóa bộ sưu tập hoặc phần tử

Tuy nhiên, điều này dường như không bao gồm khái niệm "tìm kiếm".

Ví dụ: trong việc thiết kế một bộ dịch vụ web hỗ trợ trang web Tìm kiếm việc làm, bạn có thể có các yêu cầu sau:

  • Nhận quảng cáo việc làm cá nhân
    • GET đểdomain/Job/{id}/
  • Tạo quảng cáo việc làm
    • Đăng lêndomain/Job/
  • Cập nhật quảng cáo việc làm
    • PUT đểdomain/Job/
  • Xóa quảng cáo việc làm
    • DELETE đểdomain/Job/

"Nhận tất cả các công việc" cũng đơn giản:

  • GET đểdomain/Jobs/

Tuy nhiên, làm thế nào để công việc "tìm kiếm" rơi vào cấu trúc này?

Bạn có thể cho rằng đó là một biến thể của "bộ sưu tập danh sách" và thực hiện như sau:

  • GET đểdomain/Jobs/

Tuy nhiên, các tìm kiếm thể phức tạp và hoàn toàn có thể tạo ra một tìm kiếm tạo ra chuỗi GET dài. Đó là, tham khảo một câu hỏi SO ở đây , có vấn đề khi sử dụng chuỗi GET dài hơn khoảng 2000 ký tự.

Một ví dụ có thể là trong một tìm kiếm theo khía cạnh - tiếp tục ví dụ "công việc".

Tôi có thể cho phép tìm kiếm trên các khía cạnh - "Công nghệ", "Tiêu đề công việc", "Kỷ luật" cũng như các từ khóa văn bản miễn phí, tuổi của công việc, vị trí và mức lương.

Với giao diện người dùng linh hoạt và một số lượng lớn công nghệ và chức danh công việc, việc tìm kiếm có thể bao gồm một số lượng lớn các lựa chọn khía cạnh là khả thi.

Tinh chỉnh ví dụ này cho CV, thay vì công việc, mang lại nhiều khía cạnh hơn nữa và bạn có thể dễ dàng tưởng tượng ra một tìm kiếm với hàng trăm khía cạnh được chọn, hoặc thậm chí chỉ 40 mặt, mỗi mặt dài 50 ký tự (ví dụ: Tên công việc, Tên trường đại học, Tên nhà tuyển dụng).

Trong tình huống đó, có thể mong muốn di chuyển PUT hoặc POST để đảm bảo dữ liệu tìm kiếm sẽ được gửi chính xác. Ví dụ:

  • Đăng lêndomain/Jobs/

Nhưng về mặt ngữ nghĩa đó là một hướng dẫn để tạo ra một bộ sưu tập.

Bạn cũng có thể nói rằng bạn sẽ thể hiện điều này như là việc tạo ra một tìm kiếm:

  • Đăng lêndomain/Jobs/Search/

hoặc (như được đề xuất bởi burngramma bên dưới)

  • Đăng lêndomain/JobSearch/

Về mặt ngữ nghĩa có vẻ có ý nghĩa, nhưng bạn không thực sự tạo ra bất cứ điều gì, bạn đang thực hiện một yêu cầu cho dữ liệu.

Vì vậy, về mặt ngữ nghĩa, đó là một GET , nhưng GET không được đảm bảo để hỗ trợ những gì bạn cần.

Vì vậy, câu hỏi là - Cố gắng giữ đúng với thiết kế RESTful nhất có thể, trong khi đảm bảo rằng tôi đang giữ trong giới hạn của HTTP, thiết kế phù hợp nhất cho tìm kiếm là gì?


3
Tôi thường có ý định sử dụng GET domain/Jobs?keyword={keyword} . Điều này hoạt động tốt với tôi :) Hy vọng của tôi là, SEARCHđộng từ sẽ trở thành một tiêu chuẩn. lập trình
viên.stackexchange.com/questions/233158 / Google

Vâng, tôi có thể thấy rằng đối với một ví dụ tầm thường thì không có vấn đề gì. Nhưng trong công cụ chúng tôi đang xây dựng, thực sự không thể tin được rằng chúng tôi sẽ kết thúc với một tìm kiếm phức tạp dẫn đến chuỗi GET dài hơn 2000 ký tự. Sau đó thì sao?
Rob Baillie

Thực sự là một điểm rất tốt. Điều gì về việc chỉ định một công nghệ nén?
Knerd

2
GET với phần thân được cho phép bởi đặc tả HTTP, có thể hoặc không được hỗ trợ bởi phần mềm trung gian (đôi khi không);) và không được ưa chuộng như một thông lệ. Điều này xuất hiện trên Stackexchange theo định kỳ. stackoverflow.com/questions/978061/http-get-with-request-body
Rob

2
Cuối cùng tôi đã có POST JobSearch tạo một thực thể tìm kiếm thực tế và trả về một jobSearchId. Sau đó NHẬN công việc? JobSearch = jobSearchId trả về bộ sưu tập công việc thực tế.
Cerad

Câu trả lời:


93

Bạn không nên quên rằng các yêu cầu GET có một số ưu điểm vượt trội so với các giải pháp khác:

1) Yêu cầu GET có thể được sao chép từ thanh URL, chúng được tiêu hóa bởi các công cụ tìm kiếm, chúng "thân thiện". Trong đó "thân thiện" có nghĩa là thông thường, yêu cầu GET không nên sửa đổi bất cứ điều gì trong ứng dụng của bạn (idempotent) . Đây là trường hợp tiêu chuẩn cho một tìm kiếm.

2) Tất cả các khái niệm này rất quan trọng không chỉ từ người dùng và công cụ tìm kiếm, mà từ quan điểm thiết kế API , kiến ​​trúc .

3) Nếu bạn tạo một cách giải quyết với POST / PUT, bạn sẽ gặp vấn đề mà bạn không nghĩ đến ngay bây giờ. Ví dụ: trong trường hợp trình duyệt, nút điều hướng quay lại / làm mới trang / lịch sử. Tất nhiên những điều này có thể được giải quyết, nhưng đó sẽ là một cách giải quyết khác, sau đó là một cách khác ...

Xem xét tất cả những lời khuyên này của tôi sẽ là:

a) Bạn sẽ có thể điều chỉnh bên trong GET của mình bằng cách sử dụng cấu trúc tham số thông minh . Trong trường hợp cực đoan, bạn thậm chí có thể tìm kiếm các chiến thuật như tìm kiếm google này , nơi tôi đặt rất nhiều tham số vẫn là một url siêu ngắn.

b) Tạo một thực thể khác trong ứng dụng của bạn như Tìm kiếm việc làm . Giả sử bạn có rất nhiều tùy chọn, có thể bạn sẽ cần lưu trữ các tìm kiếm này và quản lý chúng, vì vậy nó chỉ cần xóa ứng dụng của bạn. Bạn có thể làm việc với các đối tượng JobSearch dưới dạng toàn bộ thực thể, nghĩa là bạn có thể kiểm tra nó / sử dụng nó dễ dàng hơn .


Cá nhân tôi sẽ cố gắng chiến đấu với tất cả các móng vuốt của mình để hoàn thành nó với a) và khi tất cả hy vọng đã mất, tôi sẽ bò trở lại với những giọt nước mắt trong mắt để lựa chọn b) .


4
Để làm rõ, câu hỏi này nhằm mục đích thiết kế dịch vụ web, không phải thiết kế trang web. Vì vậy, trong khi hành vi của trình duyệt được quan tâm trong phạm vi giải thích câu hỏi rộng hơn, trong trường hợp cụ thể được mô tả, nó không có kết quả. (điểm thú vị mặc dù).
Rob Baillie

@RobBaillie Ye trình duyệt chỉ là một trường hợp sử dụng. Tôi muốn bày tỏ sự thật rằng toàn bộ tìm kiếm của bạn được thể hiện bằng một chuỗi URL. Mà có rất nhiều thoải mái trong khả năng sử dụng cùng với các điểm khác sau này trong câu trả lời.
p1100i

Tại điểm b, đây là một biến thể đơn giản của tài liệu tham khảo của riêng tôi để một POST để domain/Jobs/Search/, có lẽ với domain/JobsSearch/thay vào đó, hoặc bạn đã có nghĩa là một cái gì đó khác nhau? Bạn có thể làm rõ?
Rob Baillie

7
Tại sao tôi có ấn tượng rằng REST thường là một phần của vấn đề, chứ không phải là một phần của giải pháp?
JensG

1
"Yêu cầu GET không nên sửa đổi bất cứ điều gì trong ứng dụng của bạn (idempotent)" trong khi GET là idempotent, từ liên quan là " an toàn " ở đây. Idempotent có nghĩa là thực hiện GET trên tài nguyên hai lần cũng giống như thực hiện GET trên tài nguyên đó một lần. PUT cũng là idempotent, nhưng không an toàn, ví dụ.
Jasmijn

12

TL; DR: GET để lọc, POST để tìm kiếm

Tôi phân biệt giữa việc lọc kết quả từ việc liệt kê một bộ sưu tập so với tìm kiếm phức tạp. Thử nghiệm litmus tôi sử dụng về cơ bản là nếu tôi cần nhiều hơn lọc (dương, âm hoặc phạm vi) Tôi coi đó là một tìm kiếm phức tạp hơn yêu cầu POST.

Điều này có xu hướng được củng cố khi suy nghĩ về những gì sẽ được trả lại. Tôi thường chỉ sử dụng GET nếu tài nguyên có vòng đời gần như hoàn chỉnh (PUT, DELETE, GET, bộ sưu tập GET) . Thông thường trong một bộ sưu tập, tôi sẽ trả về một danh sách các URI là tài nguyên REST tạo nên bộ sưu tập đó. Trong một truy vấn phức tạp, tôi có thể lấy từ nhiều tài nguyên để xây dựng phản hồi (nghĩ rằng SQL tham gia) vì vậy tôi sẽ không gửi lại URI, nhưng dữ liệu thực tế. Vấn đề là dữ liệu sẽ không được thể hiện trong một tài nguyên, vì vậy tôi sẽ luôn phải trả lại dữ liệu. Đây dường như là một trường hợp cắt rõ ràng về việc yêu cầu POST.

-

Đã được một lúc và bài viết gốc của tôi hơi cẩu thả nên tôi nghĩ tôi sẽ cập nhật.

GET là lựa chọn trực quan để trả về hầu hết các loại dữ liệu, bộ sưu tập tài nguyên REST, dữ liệu có cấu trúc của tài nguyên, thậm chí tải trọng số ít (hình ảnh, tài liệu, v.v.).

POST là phương thức hấp dẫn cho mọi thứ dường như không phù hợp với GET, PUT, DELETE, v.v.

Tại thời điểm này, tôi nghĩ rằng các tìm kiếm đơn giản, lọc thực hiện trực giác có ý nghĩa thông qua GET. Các tìm kiếm phức tạp tùy thuộc vào sở thích cá nhân, đặc biệt nếu bạn đang sử dụng các hàm tổng hợp, tương quan chéo (tham gia), định dạng lại, v.v. Tôi cho rằng các tham số GET không nên quá dài và đó là một truy vấn lớn (tuy nhiên nó được cấu trúc ) thường có thể có ý nghĩa hơn như một cơ thể yêu cầu POST.

Tôi cũng xem xét khía cạnh kinh nghiệm của việc sử dụng API. Tôi thường muốn làm cho hầu hết các phương pháp dễ sử dụng và trực quan nhất có thể. Tôi sẽ chuyển các cuộc gọi linh hoạt hơn (và do đó phức tạp hơn) vào POST và trên một URI tài nguyên khác, đặc biệt nếu nó không phù hợp với hành vi của các tài nguyên REST khác trong cùng API.

Dù bằng cách nào, tính nhất quán có lẽ quan trọng hơn việc bạn đang thực hiện tìm kiếm trong GET hay POST.

Hi vọng điêu nay co ich.


1
Vì REST có ý định trừu tượng hóa việc triển khai cơ bản (ví dụ: tài nguyên không nhất thiết là một hàng trong cơ sở dữ liệu hoặc tệp trên ổ cứng, nhưng có thể là bất cứ điều gì ) Tôi không biết rằng việc sử dụng POST là điều hợp lý NHẬN khi thực hiện SQL tham gia. Giả sử bạn có một bảng trường học và một bảng trẻ em và bạn muốn có một lớp học (một trường học, nhiều trẻ em). Bạn có thể dễ dàng xác định một tài nguyên ảo và GET /class?queryParams. Từ quan điểm của người dùng, "lớp" luôn là một thứ và bạn không phải thực hiện bất kỳ phép nối SQL lạ nào.
stevendesu

Không có sự khác biệt giữa "lọc" và "tìm kiếm".
Nicholas Shanks

1
Có, một bộ lọc dựa trên các trường hiện có. Một tìm kiếm có thể chứa các mẫu phức tạp hơn nhiều, kết hợp các trường, tính toán các giá trị liên tục, v.v.
user13796

@stevendesu chính xác, đó là lý do tại sao tôi sử dụng POST cho cả hai (tạo tìm kiếm) :-)
ymajoros

@ymajoros Trừ khi bạn lưu các cụm từ tìm kiếm và kết quả tìm kiếm ở đâu đó, tôi không biết rằng POST có ý nghĩa về mặt ngữ nghĩa. Khi bạn thực hiện tìm kiếm bạn đang thực hiện yêu cầu cung cấp thông tin, bạn sẽ không cung cấp thông tin mới ở bất kỳ đâu.
stevendesu

10

Trong REST, định nghĩa tài nguyên rất rộng. Đó thực sự là tuy nhiên bạn muốn gói một số dữ liệu.

  • Thật hữu ích khi nghĩ về tài nguyên tìm kiếm như một tài nguyên thu thập. Các tham số truy vấn, đôi khi được gọi là phần có thể tìm kiếm của URI, thu hẹp tài nguyên xuống các mục mà khách hàng quan tâm.

Ví dụ: Google URI chính trỏ đến tài nguyên bộ sưu tập "liên kết đến mọi trang web trên Internet". Các tham số truy vấn thu hẹp điều đó đến các trang web bạn muốn xem.

(URI = mã định danh tài nguyên chung, trong đó URL = công cụ định vị tài nguyên chung, trong đó "http: //" quen thuộc là định dạng mặc định cho URI. Tuy nhiên, mọi người sử dụng chúng thay thế cho nhau.)

  • Vì tài nguyên bạn đang tìm kiếm trong ví dụ của bạn là bộ sưu tập công việc, nên tìm kiếm với

NHẬN trang web / công việc? Type = blah & location = here & etc = etc

(trở lại) {công việc: [{công việc: ...}]}

Và sau đó sử dụng POST, đó là phần bổ sung hoặc xử lý động từ để thêm các mục mới vào bộ sưu tập đó:

POST trang web / công việc

{việc làm: ...}

  • Lưu ý rằng đó là cấu trúc tương tự cho jobđối tượng trong từng trường hợp. Một khách hàng có thể NHẬN một tập hợp các công việc, sử dụng các tham số truy vấn để thu hẹp tìm kiếm và sau đó sử dụng cùng một định dạng cho một trong các mục để POST một công việc mới. Hoặc nó có thể lấy một trong các mục đó và PUT vào URI của nó để cập nhật mục đó.

  • Đối với các chuỗi truy vấn thực sự dài hoặc phức tạp, quy ước cho phép gửi chúng dưới dạng các yêu cầu POST thay thế. Gói các tham số truy vấn lên thành các cặp tên / giá trị hoặc các đối tượng lồng nhau trong cấu trúc JSON hoặc XML và gửi nó trong phần thân của yêu cầu. Ví dụ: nếu truy vấn của bạn có dữ liệu lồng nhau thay vì một loạt các cặp tên / giá trị. Thông số HTTP cho POST mô tả nó như là động từ nối thêm hoặc xử lý. (Nếu bạn muốn lái tàu chiến qua kẽ hở trong REST, hãy sử dụng POST.)

Tôi sẽ sử dụng nó như là kế hoạch dự phòng, mặc dù.

Những gì bạn mất khi bạn làm điều đó mặc dù là một) GET là vô giá trị - nghĩa là, nó không thay đổi bất cứ điều gì - POST thì không. Vì vậy, nếu cuộc gọi thất bại, phần mềm trung gian sẽ không tự động thử lại hoặc kết quả bộ đệm và 2) với các tham số tìm kiếm trong phần thân, bạn không thể cắt và dán URI nữa. Đó là, URI không phải là định danh cụ thể cho tìm kiếm bạn muốn.

Để phân biệt giữa "tạo" từ "tìm kiếm". Có một số tùy chọn phù hợp với thực tiễn REST:

  • Bạn có thể làm điều đó trong URI bằng cách thêm một cái gì đó vào tên của bộ sưu tập, như tìm kiếm công việc thay vì công việc. Điều đó chỉ có nghĩa là bạn đang coi bộ sưu tập tìm kiếm như một tài nguyên riêng biệt.

  • Vì ngữ nghĩa của POST là cả hai quá trình HOẶC, bạn có thể xác định các cơ quan tìm kiếm với tải trọng. Giống như {công việc: ...} so với {tìm kiếm: ...}. Tùy thuộc vào logic POST để đăng hoặc xử lý nó một cách thích hợp.

Đó là khá nhiều ưu tiên thiết kế / thực hiện. Tôi không nghĩ rằng có một quy ước rõ ràng.

Vì vậy, giống như bạn đã đặt ra, ý tưởng là xác định tài nguyên bộ sưu tập cho jobs

trang web / công việc

Tìm kiếm với các tham số GET + truy vấn để thu hẹp tìm kiếm. Các truy vấn dữ liệu dài hoặc có cấu trúc đi vào phần thân của POST (có thể là một bộ sưu tập tìm kiếm riêng). Tạo bằng POST để nối vào bộ sưu tập. Và cập nhật với PUT thành một URI cụ thể.

(FWIW quy ước kiểu với URI là sử dụng tất cả chữ thường với các từ được phân tách bằng dấu gạch nối. Nhưng điều đó không có nghĩa là bạn phải làm theo cách đó.)

. Trả lời. Tôi chỉ cần viền nó với một số quy ước và thực hành.)


Đó là một ý tưởng thú vị - tôi sẽ không cân nhắc sử dụng tải trọng để phân biệt. Nó gần như có vẻ hơi ngầm! Nhưng tôi đoán lược đồ URI không thực sự chứa bất kỳ động từ nào - đó là loại yêu cầu xác định động từ. Có thể tải trọng gần hơn về mặt ngữ nghĩa với loại yêu cầu so với URI. Mối quan tâm duy nhất là - Nó có minh bạch đối với người dùng API không?
Rob Baillie

Về mặt triển khai (chúng tôi đang sử dụng Node và Express), điều đó có thể có nghĩa là routekhông thể thực sự xử lý sự lựa chọn xử lý. Tôi phải xem cái đó ...
Rob Baillie

Tôi có cùng cảm giác như vậy, rằng tách nó bằng URI có vẻ sạch hơn. Tôi là loại đi và về; đó là một cuộc gọi phán xét. Tuy nhiên, ngữ nghĩa của HTTP sẽ cho phép đưa nó vào phần thân. Tôi muốn nói, REST được mô phỏng theo World Wide Web và WWW được xây dựng với GET và POST.
Rob

8

Tôi thường sử dụng các truy vấn OData, chúng hoạt động như một cuộc gọi GET nhưng cho phép bạn hạn chế các thuộc tính được trả về và lọc chúng.

Bạn sử dụng các mã thông báo như $select=$filter=vì vậy bạn sẽ kết thúc bằng một URI trông giống như thế này:

/users?$select=Id,Name$filter=endswith(Name, 'Smith')

Bạn cũng có thể làm phân trang sử dụng $skip$topvà đặt hàng.

Để biết thêm thông tin, hãy xem OData.org . Bạn chưa chỉ định ngôn ngữ nào bạn đang sử dụng, nhưng nếu là ASP.NET, nền tảng WebApi hỗ trợ các truy vấn OData - đối với các ngôn ngữ khác (PHP, v.v.) có thể có các thư viện bạn có thể sử dụng để dịch chúng thành các truy vấn cơ sở dữ liệu.


6
Một liên kết thú vị và đáng xem, nhưng liệu nó có giải quyết được vấn đề cơ bản được mô tả, rằng các yêu cầu GET không hỗ trợ hơn 2000 ký tự trong chuỗi truy vấn và hoàn toàn có khả năng truy vấn thể dài hơn thế này không?
Rob Baillie

@RobBaillie Tôi không nghĩ vậy vì đây vẫn là một cuộc gọi GET với chuỗi truy vấn. Tôi khuyên bạn nên sử dụng OData bất cứ nơi nào bạn có thể vì đó là tiêu chuẩn để truy vấn các nguồn dữ liệu web và trong một vài lần (nếu có), truy vấn cần phức tạp đến mức bạn không thể phù hợp với truy vấn 2000 ký tự, hãy tạo một truy vấn cụ thể điểm cuối mà bạn thực hiện cuộc gọi NHẬN tới
Trevor Pilley

Bạn có thể giải thích cách tiếp cận của bạn cho "điểm cuối cụ thể mà bạn thực hiện cuộc gọi GET" không? Làm thế nào bạn có thể tưởng tượng rằng điểm cuối sẽ trông như thế nào?
Rob Baillie

@RobBaillie chắc chắn - một lần nữa tôi không chắc bạn đang sử dụng công nghệ nào nhưng trong ASP.NET tôi sẽ tạo một bộ điều khiển cụ thể được gọi JobsNearMeAddedInTheLast7Dayshoặc bất cứ điều gì để đóng gói truy vấn quá dài / phức tạp đối với OData và sau đó chỉ hiển thị thông qua các cuộc gọi GET .
Trevor Pilley

1
Tôi hiểu rồi. Một suy nghĩ thú vị khác có lẽ có một số chân, mặc dù tôi không chắc điều này sẽ giúp ích trong trường hợp cụ thể của tôi - tìm kiếm theo khía cạnh với rất nhiều loại khía cạnh và rất nhiều giá trị khía cạnh có thể
Rob Baillie

5

Một cách tiếp cận để xem xét là điều trị tập các truy vấn có thể là một nguồn tài nguyên bộ sưu tập, ví dụ /jobs/filters.

POSTcác yêu cầu đối với tài nguyên này, với các tham số truy vấn trong phần thân, sẽ tạo tài nguyên mới hoặc xác định bộ lọc tương đương hiện có và trả về một URL chứa ID của nó : /jobs/filters/12345.

Id sau đó có thể được sử dụng trong yêu cầu GET cho công việc : /jobs?filter=12345. Các GETyêu cầu tiếp theo trên tài nguyên bộ lọc sẽ trả về định nghĩa của bộ lọc.

Cách tiếp cận này có lợi thế là nó giải phóng bạn khỏi định dạng tham số truy vấn cho định nghĩa bộ lọc, có khả năng cung cấp cho bạn nhiều sức mạnh hơn để xác định các bộ lọc phức tạp. Điều kiện HOẶC là một ví dụ mà tôi có thể nghĩ rằng khó thực hiện với chuỗi truy vấn.

Một nhược điểm của phương pháp này là bạn mất khả năng đọc URL (mặc dù điều này có thể được giảm thiểu bằng cách truy xuất định nghĩa mặc dù GETyêu cầu đối với tài nguyên bộ lọc). Vì lý do này, bạn cũng có thể muốn hỗ trợ cùng hoặc một tập hợp con của các tham số truy vấn trên /jobstài nguyên như bạn sẽ hỗ trợ cho tài nguyên bộ lọc. Điều này có thể được sử dụng cho các truy vấn ngắn hơn. Nếu tính năng này được cung cấp, để duy trì năng bộ nhớ cache giữa hai loại lọc, khi sử dụng các thông số truy vấn trên các /jobsnguồn lực, thực hiện, nếu trong nội bộ tạo / tái sử dụng một nguồn lực lọc và trả về một 302hoặc 303trạng thái cho biết URL trong hình thức /jobs?filter=12345.


Phản ứng đầu tiên của tôi về điều này là trong khi đó là thông tin tốt, thì đó thực sự chỉ là một biến thể của câu trả lời được cung cấp bởi @burninggramma. Về cơ bản, đó là "tạo một thực thể mới gọi là bộ lọc / tìm kiếm, gọi để tạo ra nó và sau đó gọi để lấy nó". Biến thể là cuộc gọi để lấy nó giống như một cuộc gọi để áp dụng nó vào bộ sưu tập. Hấp dẫn. Tuy nhiên, cả câu trả lời của bạn và burngramma đều gặp phải cùng một vấn đề - tôi không muốn tạo các bộ lọc. Sẽ có một số lượng lớn trong số chúng và chúng không cần được lưu trữ ngoại trừ để duy trì triển khai RESTful.
Rob Baillie

2
Rõ ràng, các tham số truy vấn là giải pháp tốt nhất, nhưng câu hỏi của bạn đặc biệt hỏi về cách xử lý các định nghĩa bộ lọc dài hơn giới hạn đối với các URL được áp đặt bởi một số máy chủ. Để giải quyết giới hạn độ dài, bạn cần phải nén chuỗi truy vấn bằng cách nào đó hoặc bạn cần sử dụng phương thức yêu cầu hỗ trợ chỉ định phần thân có độ dài tùy ý. Nếu bạn không muốn coi các bộ lọc là tài nguyên, chỉ cần hỗ trợ giao diện không yên tĩnh nơi các định nghĩa bộ lọc được POST. Bạn sẽ mất khả năng lưu trữ bộ nhớ cache, nhưng nếu dữ liệu của bạn đủ biến động thì nó sẽ không được hưởng lợi từ bộ nhớ đệm.
pgraham

Bạn có thể khắc phục nhu cầu lưu trữ các bộ lọc bằng cách đơn giản là ... không lưu trữ chúng. Không có gì về REST đảm bảo rằng nó bền bỉ. Bạn có thể đưa ra yêu cầu GET /jobs/37và nhận kết quả, sau đó ai đó xóa tài nguyên và 2 giây sau đó, cùng một yêu cầu sẽ trả về 404. Tương tự nếu bạn POST /searchesvà bạn được chuyển hướng đến kết quả tìm kiếm (tìm kiếm được tạo và bạn nhận được 201 với Tiêu đề vị trí cho tài nguyên), 2 giây sau kết quả đó có thể bị xóa khỏi bộ nhớ và phải được tạo lại. Không cần lưu trữ lâu dài.
stevendesu

5

Đây là một câu trả lời cũ nhưng tôi vẫn có thể đóng góp một chút cho cuộc thảo luận. Tôi đã quan sát rất thường xuyên một sự hiểu lầm về REST, RESTful và Architecture. RESTful không bao giờ đề cập đến bất cứ điều gì về việc KHÔNG xây dựng tìm kiếm, không có gì trong RESTful về kiến ​​trúc, đó là một tập hợp các nguyên tắc hoặc tiêu chí thiết kế.

Để mô tả Tìm kiếm theo cách tốt hơn, chúng ta phải nói về một kiến ​​trúc nói riêng và kiến ​​trúc phù hợp hơn là Kiến trúc hướng tài nguyên (ROA).

Trong RESTful có các nguyên tắc để thiết kế, idempotent không có nghĩa là kết quả không thể thay đổi khi tôi đọc trong một số câu trả lời, điều đó có nghĩa là kết quả của một yêu cầu độc lập không phụ thuộc vào số lần thực hiện. Nó có thể thay đổi, hãy tưởng tượng rằng tôi liên tục cập nhật cơ sở dữ liệu cung cấp cho nó một số dữ liệu được phục vụ bởi Api RESTful, thực thi cùng một GET có thể thay đổi kết quả nhưng nó không phụ thuộc vào số lần thực thi. Nếu tôi có thể đóng băng thế giới, điều đó có nghĩa là không có trạng thái, chuyển đổi, bất cứ điều gì bên trong dịch vụ khi tôi yêu cầu tài nguyên dẫn đến một kết quả khác.

Theo định nghĩa, tài nguyên là bất cứ thứ gì quan trọng để được tham chiếu như một thứ.

Trong một kiến ​​trúc hướng tài nguyên (hãy gọi nó là ROA từ bây giờ để đơn giản), chúng tôi tập trung vào tài nguyên có thể có rất nhiều thứ:

  • Một phiên bản của một tài liệu
  • Phiên bản cập nhật cuối cùng của tài liệu
  • Một kết quả đến từ một tìm kiếm
  • Một danh sách các đối tượng
  • Bài viết đầu tiên tôi mua từ một thương mại điện tử

Điều làm cho nó trở nên độc đáo về mặt tài nguyên là khả năng bổ sung có nghĩa là nó chỉ có một URI

Theo cách đó, tìm kiếm phù hợp hoàn hảo trong RESTful khi xem xét ROA . Chúng tôi phải sử dụng GET vì tôi cho rằng tìm kiếm của bạn là một tìm kiếm bình thường và nó không thay đổi bất cứ điều gì, vì vậy nó không hoạt động (ngay cả khi nó trả về những thứ khác nhau tùy thuộc vào các yếu tố mới được thêm vào). Có một sự nhầm lẫn ở đây theo cách đó bởi vì tôi có thể dính vào RESTful chứ không phải ROA, điều đó có nghĩa là tôi có thể theo một mô hình tạo ra một tìm kiếm và trả về những thứ khác nhau với cùng một tham số vì tôi không sử dụng nguyên tắc địa chỉ của ROA. Làm như thế nào? Chà, nếu bạn gửi các bộ lọc tìm kiếm trong phần thân hoặc tiêu đề thì tài nguyên không phải là ĐỊA CHỈ.

Bạn có thể tìm thấy các nguyên tắc chính xác và URI trong tài liệu gốc W3:

https://www.w3.org/DesignIssues/Axioms

Bất kỳ URL nào trong kiến ​​trúc này phải tự mô tả. Điều này là cần thiết nếu bạn tuân theo các nguyên tắc để giải quyết mọi thứ trong URI, điều đó có nghĩa là bạn có thể sử dụng / (dấu gạch chéo) để phân tách bất cứ thứ gì bạn cần hoặc tham số truy vấn. Chúng tôi biết có những hạn chế về điều đó nhưng đây là mô hình kiến ​​trúc.

Theo mẫu ROA trong RESTful, một tìm kiếm không nhiều hơn bất kỳ tài nguyên nào khác, sự khác biệt duy nhất là các tài nguyên đến từ một tính toán thay vì liên quan trực tiếp đến chính đối tượng. Dựa trên nguyên tắc tôi có thể giải quyết và có được một dịch vụ tính toán số học đơn giản dựa trên mẫu sau:

http://myapi.com/sum/1/2

Trong đó tổng, 1 và 2 có thể được sửa đổi nhưng kết quả tính toán là duy nhất và có thể thay đổi được, mỗi lần tôi gọi với cùng tham số tôi đều nhận được cùng một dịch vụ và không có gì thay đổi trong dịch vụ. Resouce / sum / 1/2 và / sub / 5/4 bám sát các nguyên tắc một cách hoàn hảo.


3

GET là ok, nếu bạn có một bộ sưu tập tĩnh luôn trả về cùng kết quả (đại diện) cho một URI. Điều đó cũng ngụ ý rằng dữ liệu tạo ra các biểu diễn này không bao giờ bị thay đổi. Nguồn là một cơ sở dữ liệu chỉ đọc.

Việc GET trả về các kết quả khác nhau cho một và cùng một URI vi phạm tính không ổn định / an toànnguyên tắc CoolURI và do đó không phải là RESTful . Có thể có các động từ idempotent ghi vào cơ sở dữ liệu, nhưng chúng không bao giờ phải ảnh hưởng đến việc biểu diễn.

Một tìm kiếm chung bắt đầu với một yêu cầu POST trả về một tham chiếu đến kết quả. Nó tạo ra kết quả (nó là mới và có thể được tìm nạp với một GET tiếp theo). Tất nhiên, kết quả này có thể được phân cấp (tham chiếu thêm với các URI mà bạn có thể NHẬN), và có thể sử dụng lại các yếu tố của các tìm kiếm trước đó, nếu nó có ý nghĩa đối với ứng dụng.

Nhân tiện, tôi biết mọi người làm điều đó khác nhau. Bạn không cần phải giải thích cho tôi việc vi phạm REST có thể thuận tiện đến mức nào.


Aaaaaaaah - vậy đó là cách nó hoạt động! Cảm ơn!
Rob Baillie

1
Idempotency không có nghĩa là nó phải luôn trả lại chính xác như nhau, nó phải trả lại như cũ nếu KHÔNG thay đổi. Tìm kiếm có thể được coi là kết quả của một tính toán và bản thân nó là một tài nguyên.
Maximiliano Rios

Idempotency thực sự có nghĩa là kết quả vẫn như cũ. Bạn có thể, và có thể sử dụng điều khiển bộ đệm. Và tất nhiên bạn có thể sử dụng XÓA để can thiệp vào các GET sau này. Tuy nhiên, nếu một tác nhân cần giữ kiến ​​thức về hoạt động bên trong của ứng dụng, thì nó không còn RESTful nữa. Ở trên, tôi đã nói về ý tưởng cực đoan nhất về REST. Trong thực tế, mọi người có thể vi phạm nhiều khía cạnh của nó. Họ đang trả giá khi bộ nhớ cache không lưu cache hiệu quả nữa.
Martin Sugioarto

"Idempotency thực sự có nghĩa là kết quả vẫn như cũ." ... Sau khi yêu cầu. Tôi tin rằng vấn đề là yêu cầu đó không thay đổi dữ liệu.
AndreiMotea
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.