Một cách thích hợp để làm một phương pháp tìm kiếm RESTful phức tạp là gì?


44

Theo nguyên tắc REST, tôi muốn tạo phương thức GET cho API của mình để thực hiện tìm kiếm bằng một số tiêu chí và trả về kết quả cho khách hàng. Vấn đề là các tiêu chí có thể có tối đa 14 tham số, một trong số đó là danh sách các đối tượng phức tạp, vì vậy ...

  • Tôi thậm chí không biết liệu có thể mã hóa / giải mã các đối tượng phức tạp này thành / từ các tham số url hay không.

  • Tôi không tính được url có thể nhận được bao lâu nhưng tôi chắc chắn nó sẽ đủ lớn và có thể đạt đến giới hạn chiều dài url?

Ngoài ra, tìm kiếm sẽ hiển thị kết quả theo "thời gian thực", ý tôi là, mỗi khi người dùng thay đổi thứ gì đó từ mẫu tìm kiếm, anh ta sẽ có thể thấy kết quả mới mà không cần nhấn bất kỳ nút "tìm kiếm" nào.

Bạn có thể làm rõ cho tôi những điểm này và lời khuyên của bạn là gì để tạo ra một phương pháp tìm kiếm yên tĩnh với nhiều tham số?


3
Bên cạnh đó (tôi lưu ý rằng cả hai câu trả lời tại thời điểm viết đều đề cập đến phần thời gian thực), các tìm kiếm thời gian thực thường chỉ nên gửi yêu cầu cập nhật nhiều lần. Ví dụ, trong khi bạn đang gõ, bạn sẽ được gửi yêu cầu cho các công cụ như search?q=t, search?q=te, search?q=test, và vân vân. Xem xét việc giới hạn tần suất truy vấn được gửi để tránh làm tổn thương máy chủ của bạn. Bạn cũng có thể trả lại rất nhiều thông tin và về phía khách hàng thực hiện lọc. Điều đó hoạt động tốt nếu người dùng nhập các danh mục rộng có thể thu hẹp mọi thứ rất nhiều.
Kat

2
Bất kể giải pháp nào, hãy đảm bảo trao đổi dữ liệu ở định dạng trung tính về công nghệ. Vì vậy, không sử dụng một đại diện nội bộ hoặc sẽ khó hơn để viết ứng dụng khách cho API của bạn.
Kwebble

Tùy thuộc vào nhu cầu của bạn, thư viện này có thể thực hiện công việc: github.com/jiruska/rsql-parser . Nó có tiện ích mở rộng JPA nếu bạn sử dụng JPA hoặc bạn có thể viết Khách truy cập của riêng mình để ánh xạ tới API của công cụ tìm kiếm. Và bạn có thể thêm toán tử của riêng bạn.
Walfrat

Câu trả lời:


54

Trước khi bạn đọc câu trả lời của tôi, tôi muốn nói rằng tôi đã đồng ý với @Neil. Chúng tôi phải chọn các trận chiến của chúng tôi. Chúng tôi thường muốn làm hết sức mình, nhưng đôi khi có quá ít chỗ để thảo luận và chúng tôi phải đưa ra quyết định trái với ý muốn của chúng tôi.

Dù sao, trong câu trả lời của Neil, tôi bỏ lỡ một điều nữa. Tài liệu . Chỉ để đảm bảo rằng các nhà phát triển biết rằng các yêu cầu POST /searchđược an toàn.

Mà nói.

1. Cho một cơ hội để NHẬN

Hãy xem xét GETlựa chọn đầu tiên. Kiểm tra độ dài tối đa của URL câu hỏi này . Đánh giá xem chuỗi truy vấn dài nhất của bạn có dài hơn 2000 ký tự hay không. Nếu không, và bạn không mong đợi nó xảy ra, hãy đi cùng GET. Nó có vẻ xấu, nhưng ít nhất bạn có thể đánh dấu URL và tất nhiên, nó có tất cả các lợi thế xuất phát từ ngữ nghĩa của phương thức (idempotence, an toàn và bộ nhớ đệm)

1.1 Thử mã hóa chuỗi truy vấn

Ví dụ: trong cơ sở 64. Ngay cả javascript cũng hỗ trợ mã hóa cơ sở 64 .

Đây là cách nó hoạt động:

  1. Xây dựng JSON với tất cả các bộ lọc và chuẩn hóa nó.
  2. Phân tích nó thành chuỗi
  3. Mã hóa nó
  4. Gửi JSON được mã hóa theo yêu cầu param ( /search?q=SGVsbG8gV29ybGQh....).
  5. Về phía máy chủ, giải mã param q .
  6. Giải nén chuỗi JSON

Trước đây, tạo chuỗi JSON dài nhất có thể, mã hóa nó và lấy độ dài. Đánh giá nếu chuỗi được mã hóa phù hợp với URL. Tôi đã triển khai đoạn mã sau trên Fiddle.js để bạn kiểm tra. (Tôi hy vọng nó vẫn hoạt động) 1

Mã hóa cơ sở 64 có tính xác định và có thể đảo ngược, do đó không có cơ hội va chạm.

Với các truy vấn được mã hóa, chúng tôi cũng có thể lưu các tìm kiếm trong DB, đánh dấu URL, chia sẻ liên kết, v.v. Và tất nhiên, chúng tôi không phải thoát / hủy bỏ chuỗi.

1.2 Thử với bí danh

Đọc blog này về cách thiết kế API REST, tôi nhớ thêm một lựa chọn khác. Bí danh cho các truy vấn phổ biến .

Tôi thấy những điều này là thú vị cho những lý do tiếp theo

  • Rút ngắn độ dài chuỗi truy vấn. Nó làm cho API sạch hơn và thân thiện với người dùng

    NHẬN / vé /? Status = đã đóng & đã đóngAt = xxx so với GET / vé / gần đây đã đóng /

  • Kết hợp với nhiều bí danh hoặc nhiều tham số yêu cầu hơn.

    NHẬN / vé /? Status = đã đóng & đã đóngAt = xxx & trong vòng = 30 phút so với NHẬN / vé / gần đây đã đóng /? Trong vòng = 30 phút

  • Chúng ta có thể kết hợp bí danh với các chuỗi truy vấn được mã hóa

    NHẬN / vé /? Status = đã đóng & đã đóngAt = xxx & trong vòng 30 phút so với NHẬN / vé / đã đóng gần đây /? Q = SGVsbG8g ...


1: Tôi đã sử dụng JSON, nhưng chúng tôi có thể sử dụng các định dạng khác ngay khi chúng tôi có thể giải tuần tự hóa nó ở phía máy chủ.


2
Điều này là cả thực tế và chính xác. Một điều đáng chú ý là hầu hết các ngôn ngữ lập trình đều biến việc băm thành chuỗi truy vấn trở nên tầm thường, do đó, bắt đầu bằng hành động GET là rất dễ thực hiện.
Aluan Haddad

1
Tôi yêu Spring stackoverflow.com/questions/16942193/ Tôi không thể tin rằng nó đã hoạt động ngay lần thử đầu tiên: D. Về chiều dài url, chưa đến 1k, mặc dù chúng ta vẫn cần lặp lại thông số kỹ thuật.
anat0lius

Sau đó, đi với NHẬN. Để đơn giản. Với Spring MVC, bạn có thể đạt được ánh xạ rất giống với GET. Tìm kiếm WebArgumentResolver của Spring ;-)
Laiv

Base64 làm tăng kích thước tải trọng khoảng 4/3. Trong khi urlencoding có thể làm cho nó 3/1 cho các ký tự đặc biệt, các truy vấn có ký tự chủ yếu là an toàn sẽ giữ nguyên kích thước. Có bất kỳ lý do khác để sử dụng cơ sở64?
biệt thự

Không hẳn vậy. Tôi chỉ không thích (un) thoát URL. Sự quá tải của tải trọng là sự đánh đổi ở đây. Nó vẫn phải vừa với kích thước tối đa của GET cho mỗi yêu cầu. Đó là lý do tại sao tôi xây dựng đoạn trích. Để người dùng thử. Khi tôi viết câu trả lời, tôi đã ưu tiên ngữ nghĩa web hơn các chi tiết triển khai. Toàn bộ câu trả lời là "tiếp tục cố gắng với GET". Tìm theo cách của bạn hoặc sử dụng bất kỳ trong số này tôi chia sẻ với bạn.
Laiv

13

Nếu tất cả những gì bạn có là một cái búa, mọi thứ trông giống như một cái đinh. Có vẻ như vấn đề ở đây là bạn đang cố gắng biến một trang tìm kiếm thành một trang RESTful và điều này dường như khó có thể là một mô hình chung cho thiết kế RESTful để giải quyết.

Chỉ cần đi với một yêu cầu POST với các tham số do người dùng cung cấp để có được thông tin bạn yêu cầu từ phụ trợ. Tôi cho rằng bạn không cần phải làm gì ngoài việc thực hiện tìm kiếm, vì vậy không có cơ hội bạn sẽ cần phải chèn qua trang này. Chỉ cần thêm một / tìm kiếm vào cuối URL của bạn để bạn không gặp rủi ro khi xung đột với trang / người dùng của bạn sẽ là RESTful.


2
@LiLou_: Đối với yêu cầu đó, chỉ có hai khả năng thực tế: 1. Đọc tất cả dữ liệu về giao diện người dùng của bạn và thực hiện lọc ở đó. Điều này có thể bị cấm trong số lượng bộ nhớ cần thiết. 2. Thực hiện một yêu cầu mới đến máy chủ cho mỗi thay đổi trong tiêu chí tìm kiếm. Sẽ không có vấn đề gì nếu đây là một yêu cầu POST hoặc GET, nhưng độ trễ mạng liên quan có thể gây gián đoạn cho ý nghĩa cập nhật "thời gian thực" của người dùng.
Bart van Ingen Schenau 19/07/17

2
Tôi đồng ý không đồng ý, POST có nghĩa là một cái gì đó khác về mặt ngữ nghĩa. Tôi sẽ đề nghị sử dụng GET và chuyển tất cả dữ liệu bộ lọc trong tham số truy vấn ngay bây giờ nếu có quá nhiều tham số thì đó là lỗi ở cấp ứng dụng.
CodeYogi

2
@CodeYogi đôi khi khách hàng không cung cấp cho bạn không gian để phân biệt. Tôi đã triển khai các trang xem giống như Excel với 40-50 cột mỗi trang với bộ lọc riêng. Và sắp xếp tất nhiên. Dù sao, vẫn có thể với GET nhưng có vẻ không quá thời trang
Laiv

1
@Laiv trong trường hợp đó cần phải thảo luận nghiêm túc vì POST có nghĩa là để thay đổi trạng thái máy chủ. Các trường hợp sử dụng như thế này không phải là ngoại lệ do đó nên được quan tâm mà không cần hack.
CodeYogi

2
Trong các trường hợp luận án, tài liệu là phải. Tôi đã có một cuộc thảo luận nghiêm túc với khách hàng về khả năng sử dụng các ứng dụng của họ. Sau đó tôi đã được chứng minh là đúng vì người dùng cuối đã đồng ý với tôi. Tuy nhiên, đôi khi bạn phải chọn các trận đánh của bạn.
Laiv

0

Nó hoàn toàn phụ thuộc vào mô hình API của bạn là gì: Không có hoặc dưới dạng động từ.

Nếu API là không có thì bạn có thể muốn lấy danh sách các đối tượng như sau:

GET: /api/v1/objects

Trong trường hợp này, bạn phải gửi dữ liệu dưới dạng tham số yêu cầu. Vì vậy, bạn phải mô tả các tham số của mình dưới dạng một danh sách phẳng các giá trị khóa:

GET: /api/v1/objects

key1 : val1
key2.key1 : val 21
key2.key2 : val 22
....

Một số nền tảng hỗ trợ trình phân giải tham số tùy chỉnh (ví dụ Spring MVC), bạn có thể chuyển đổi các tham số thành một đối tượng.

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.