Jaki jest właściwy sposób wykonania złożonej metody wyszukiwania RESTful?


44

Zgodnie z zasadami REST chciałbym utworzyć metodę GET dla mojego interfejsu API, która przeprowadzi wyszukiwanie przy użyciu niektórych kryteriów i zwróci wyniki klientowi. Problem polega na tym, że kryteria mogą mieć do 14 parametrów, jednym z nich jest lista złożonych obiektów, więc ...

  • Nie wiem nawet, czy można zakodować / zdekodować te złożone obiekty do / z parametrów adresu URL.

  • Nie obliczyłem, jak długi może być adres URL, ale jestem pewien, że będzie on wystarczająco duży i być może osiągnie limit długości adresu URL?

Ponadto wyszukiwanie powinno pokazywać wyniki w „czasie rzeczywistym”, to znaczy za każdym razem, gdy użytkownik zmienia coś z formularza wyszukiwania, powinien być w stanie zobaczyć nowe wyniki bez naciskania żadnego przycisku „wyszukiwania”.

Czy mógłbyś mi wyjaśnić te kwestie i jaka byłaby twoja rada, aby stworzyć metodę wyszukiwania opartą na wielu parametrach?


3
Na marginesie (zauważam, że żadna z dwóch odpowiedzi w momencie pisania nie wspomina o części w czasie rzeczywistym), wyszukiwania w czasie rzeczywistym zwykle powinny po prostu wysyłać zaktualizowane żądanie w kółko. Na przykład podczas pisania, byłbyś wysyłania żądań do rzeczy jak search?q=t, search?q=te, search?q=testi tak dalej. Rozważ ograniczenie częstotliwości wysyłania zapytania, aby uniknąć uszkodzenia serwera. Możesz również zwrócić wiele informacji i po stronie klienta przeprowadzić filtrowanie. Działa to dobrze, jeśli użytkownik wprowadza szerokie kategorie, które mogą znacznie zawęzić zakres.
— Kat

2
Bez względu na rozwiązanie pamiętaj o wymianie danych w neutralnym technologicznie formacie. Więc nie używaj wewnętrznej reprezentacji, bo trudniej będzie napisać klientów dla twojego API.
— Kwebble

W zależności od potrzeb ta biblioteka może wykonać zadanie: github.com/jirutka/rsql-parser . Ma rozszerzenie JPA, jeśli używasz JPA, lub możesz napisać własnego gościa, aby zmapować go do interfejsu API swojej wyszukiwarki. I możesz dodać własnego operatora.
— Walfrat

Odpowiedzi:


54

Zanim przeczytasz moją odpowiedź, chciałbym powiedzieć, że zgodziłem się z @Neil. Musimy wybrać nasze bitwy. Zwykle chcemy dać z siebie wszystko, ale czasem jest za mało miejsca na dyskusje i musimy podejmować decyzje wbrew naszej woli.

W każdym razie, w odpowiedzi Neila, brakuje mi jeszcze jednej rzeczy. Dokumentacja . Aby upewnić się, że programiści wiedzą, że żądania POST /searchsą bezpieczne.

To mówi.

1. Daj szansę GET

GETNajpierw rozważ opcję. Sprawdź maksymalną długość adresu URL tego pytania . Oceń, czy najdłuższy ciąg zapytania ma więcej niż 2000 znaków. Jeśli tak nie jest i nie spodziewasz się, że tak będzie, idź z GET. Może się to wydawać brzydkie, ale przynajmniej możesz dodać do zakładek adres URL i, oczywiście, ma wszystkie zalety wynikające z semantyki metody (idempotencja, bezpieczeństwo i buforowanie)

1.1 Spróbuj zakodować ciąg zapytania

Na przykład w bazie 64. Nawet javascript obsługuje kodowanie bazy 64 .

Oto jak to działa:

  1. Zbuduj JSON ze wszystkimi filtrami i znormalizuj go.
  2. Parsuj to na string
  3. Zakoduj to
  4. Wyślij zakodowany JSON jako żądanie param ( /search?q=SGVsbG8gV29ybGQh....).
  5. Po stronie serwera zdekoduj parametr q .
  6. Deserializuj ciąg JSON

Wcześniej wykonaj najdłuższy możliwy ciąg JSON, zakoduj go i przyjmij długość. Oceń, czy zakodowany ciąg pasuje do adresu URL. Zaimplementowałem następujący fragment kodu w Fiddle.js do przetestowania. (Mam nadzieję, że nadal działa) 1

Podstawowe kody 64 są deterministyczne i odwracalne, więc nie ma szans na kolizje.

Za pomocą zakodowanych zapytań możemy również zapisywać wyszukiwania w bazie danych, dodawać do zakładek adres URL, udostępniać linki itp. I oczywiście nie musimy uciekać / usuwać scen z łańcucha.

1.2 Spróbuj użyć aliasów

Czytając ten blog na temat projektowania interfejsów API REST, przypomniałem sobie jeszcze jedną alternatywę. Aliasy dla typowych zapytań .

Uważam, że są interesujące z następujących powodów

  • Skróć długość ciągu zapytania. Dzięki temu interfejs API jest czystszy i przyjazny dla użytkownika

    GET / bilety / status = zamknięte i zamknięte At = xxx vs GET / bilety / ostatnio zamknięte /

  • Można łączyć z większą liczbą aliasów lub większą liczbą parametrów żądania.

    GET / bilety / status = zamknięte i zamknięte At = xxx i w ciągu = 30 minut vs GET / bilety / ostatnio zamknięte / w ciągu = 30 minut

  • Możemy łączyć aliasy z zakodowanymi ciągami zapytań

    GET / bilety /? Status = zamknięte i zamknięte At = xxx i w ciągu = 30 min vs GET / bilety / ostatnio zamknięte /? Q = SGVsbG8g ...


1: Użyłem JSON, ale moglibyśmy użyć innych formatów, jak tylko moglibyśmy dokonać deserializacji po stronie serwera.


2
Jest to zarówno praktyczne, jak i prawidłowe. Warto również zauważyć, że większość języków programowania sprawia, że ​​przekształcanie skrótu w ciąg zapytania jest banalne, więc rozpoczęcie od działania GET jest bardzo łatwe.
— Aluan Haddad

1
Uwielbiam Spring stackoverflow.com/questions/16942193/... Nie mogę uwierzyć, że zadziałało za pierwszym razem: D. Informacje o długości adresu URL wynoszą mniej niż 1 tys., Choć nadal musimy iterować specyfikacje.
— anat0lius

Następnie przejdź z GET. Dla prostoty. Dzięki Spring MVC możesz uzyskać to samo mapowanie za pomocą GET. Spójrz na WebArgumentResolver wiosennego ;-)
— LAIV

Base64 napełnia rozmiar ładunku o około 4/3. Chociaż urlencoding może sprawić, że będzie to 3/1 dla znaków specjalnych, zapytania z przeważnie bezpiecznymi znakami będą miały ten sam rozmiar. Czy jest jakiś inny powód, aby używać base64?
— villasv

Nie całkiem. Po prostu nie lubię (nie) ucieczkowych adresów URL. Przeważenie ładunku jest tutaj kompromisem. Nadal musi mieścić się w maksymalnym rozmiarze GET na żądanie. Właśnie dlatego zbudowałem fragment kodu. Do wypróbowania przez użytkownika. Kiedy napisałem odpowiedź, nadałem priorytet semantyce internetowej nad szczegółami implementacji. Sedno odpowiedzi brzmi: „próbuj z GET”. Znajdź swoją drogę lub skorzystaj z tych, które Ci udostępniam.
— Laiv

13

Jeśli masz tylko młotek, wszystko wygląda jak gwóźdź. Wygląda na to, że problem polega na tym, że próbujesz zamienić stronę wyszukiwania w stronę RESTful, a to raczej nie jest powszechny wzór do rozwiązania przy projektowaniu RESTful.

Po prostu przejdź do żądania POST z parametrami podanymi przez użytkownika, aby uzyskać wymagane informacje z backendu. Zakładam, że nie musisz nic robić poza wyszukiwaniem, więc nie ma szans, że będziesz musiał wstawić tę stronę. Wystarczy dodać opcję / search na końcu swojego adresu URL, aby nie ryzykować konfliktów ze stroną / users, które byłyby RESTful.


2
@LiLou_: W przypadku tego wymogu istnieją tylko dwie realistyczne możliwości: 1. Przeczytaj wszystkie dane z interfejsu użytkownika i przeprowadź filtrowanie. Może to być zbyt wysokie w wymaganej ilości pamięci. 2. Wykonaj nowe żądanie do serwera dla każdej zmiany kryteriów wyszukiwania. Nie ma znaczenia, czy jest to żądanie POST, czy GET, ale związane z tym opóźnienie sieci może być zakłócające dla użytkownika w odczuciu aktualizacji „w czasie rzeczywistym”.
— Bart van Ingen Schenau

2
Zgodziłbym się nie zgodzić, POST oznacza coś semantycznie. Sugerowałbym pójść z GET i przekazać teraz wszystkie dane filtru w parametrze zapytania, jeśli jest zbyt wiele parametrów, to jest to błąd na poziomie aplikacji.
— CodeYogi,

2
@CodeYogi czasami klient nie daje ci miejsca na dyskuzję. Zaimplementowałem strony widoku podobne do Excela z 40-50 kolumnami, każda z własnym filtrem. I oczywiście do sortowania. W każdym razie jest to możliwe z GET, ale może nie wydawać się zbyt modne
— Laiv

1
@Laiv w takim przypadku musi być poważna dyskusja, ponieważ POST jest przeznaczony do zmiany stanu serwera. Takie przypadki użycia nie są wyjątkowe, dlatego należy się nimi zająć bez włamań.
— CodeYogi,

2
W tych przypadkach dokumentacja jest koniecznością. Przeprowadziłem poważną dyskusję z klientami na temat użyteczności ich aplikacji. Później okazało się, że miałem rację, ponieważ użytkownik końcowy zgodził się ze mną. Czasami jednak musisz wybrać swoje bitwy.
— Laiv

0

To w pełni zależy od tego, jaki jest twój model API: jako brak lub jako czasownik.

Jeśli API nie ma, możesz chcieć uzyskać listę obiektów w następujący sposób:

GET: /api/v1/objects

W takim przypadku musisz wysłać dane jako parametry żądania. Musisz więc opisać swoje parametry jako płaską listę kluczowych wartości:

GET: /api/v1/objects

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

Niektóre platformy obsługują niestandardowe narzędzie do rozwiązywania parametrów (np. Spring MVC), w którym można konwertować parametry na obiekt.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.