Який правильний спосіб зробити складний метод пошуку RESTful?


44

Дотримуючись принципів REST, я хотів би створити метод GET для свого API, який здійснює пошук за деякими критеріями і повертає результати клієнту. Проблема полягає в тому, що критерії можуть мати до 14 параметрів, один з них - це список складних об'єктів, тому ...

  • Я навіть не знаю, чи можна кодувати / декодувати ці складні об'єкти до / з параметрів URL.

  • Я не підрахував, скільки часу може отримати URL-адреса, але я впевнений, що вона буде достатньо великою і, можливо, досягне межі довжини URL-адреси?

Також пошук повинен показувати результати в режимі "реального часу", тобто кожен раз, коли користувач щось змінює з форми пошуку, він повинен мати можливість бачити нові результати, не натискаючи жодної кнопки "пошук".

Чи можете ви пояснити мені ці моменти, і що б вам порадили створити спокійний метод пошуку з великою кількістю параметрів?


3
Як осторонь (зауважу, що жодна з двох відповідей під час написання не згадує частину реального часу), пошук у режимі реального часу зазвичай повинен просто надсилати оновлений запит знову і знову. Наприклад, в той час як ви друкуєте, ви будете посилати запити на такі речі , як search?q=t, search?q=te, search?q=testі так далі. Подумайте про обмеження частоти надсилання запиту, щоб не травмувати ваш сервер. Ви також можете повернути велику кількість інформації і на стороні клієнта зробити фільтрацію. Це добре працює, якщо користувач вводить широкі категорії, які можуть суттєво звузити речі.
Кет

2
Незалежно від рішення, не забудьте обмінятися даними у технологічному нейтральному форматі. Тому не використовуйте внутрішнє представлення, інакше клієнтам для вашого API буде складніше писати.
Kwebble

Залежно від ваших потреб, ця бібліотека може зробити роботу: github.com/jirutka/rsql-parser . Він має розширення JPA, якщо ви використовуєте JPA, або ви можете написати власний відвідувач, щоб відобразити API своєї пошукової системи. І ви можете додати власного оператора.
Вальфрат

Відповіді:


54

Перш ніж прочитати мою відповідь, я хотів би сказати, що погодився з @Neil. Треба вибирати наші битви. Зазвичай ми хочемо зробити все можливе, але іноді замало місця для дискусій, і нам доводиться приймати рішення проти нашої волі.

У будь-якому випадку, у відповіді Ніла я пропускаю ще одне. Документація . Просто для того, щоб розробники знали, що POST просить /searchбути безпечними.

Це сказав.

1. Дайте шанс отримати

Розглянемо GETспочатку варіант. Перевірте максимальну довжину URL-адреси цього питання . Оцініть, чи довша ваша найдовша рядок запиту перевищує 2000 символів. Якщо це не так, і ви не очікуєте, що це буде, почніть GET. Це може здатися некрасивим, але принаймні ви можете зробити закладку URL-адреси, і, звичайно, у неї є всі переваги, отримані з семантики методу (ідентифікація, безпека та кешування)

1.1 Спробуйте кодувати рядок запиту

Наприклад, у базі 64. Навіть javascript підтримує базові кодування 64 .

Ось як це працює:

  1. Побудуйте JSON з усіма фільтрами та нормалізуйте його.
  2. Розбираємо його на рядок
  3. Зашифруйте його
  4. Відправити закодований JSON як параметр запиту ( /search?q=SGVsbG8gV29ybGQh....).
  5. На стороні сервера розшифруйте параметр q .
  6. Десеріалізуйте рядок JSON

Попередньо зробіть найдовший можливий рядок JSON, закодуйте його та візьміть довжину. Оцініть, чи відповідає кодований рядок в URL-адресі. Я реалізував наступний фрагмент на Fiddle.js для тестування. (Я сподіваюся, що це все ще працює) 1

Базові коди 64 є детермінованими та оборотними, тому немає шансів на зіткнення.

За допомогою закодованих запитів ми також могли б зберігати пошукові запити в БД, закладку URL-адреси, спільне використання посилань тощо. І, звичайно, нам не потрібно уникати / не скасовувати рядок.

1.2 Спробуйте з псевдонімами

Читаючи цей блог про те, як створити API REST, я згадав ще одну альтернативу. Псевдоніми для загальних запитів .

Мені це здається цікавим з наступних причин

  • Скоротіть довжину рядка запиту. Це робить API більш чистим та зручним для користувачів

    GET / квитки /? Status = closed & closedAt = xxx проти GET / квитки / нещодавно закриті /

  • Поєднується з більшою кількістю псевдонімів або більше параметрів запиту.

    GET / квитки /? Статус = закритий та закритийAt = xxx та протягом = 30 хв проти GET / квитки / недавно закриті /? В межах = 30 хв

  • Ми можемо комбінувати псевдоніми з кодованими рядками запитів

    GET / квитки /? Статус = закритий та закритийAt = xxx та протягом = 30 хв. Проти GET / квитки / недавно закриті /? Q = SGVsbG8g ...


1: Я використовував JSON, але ми могли використати інші формати, як тільки зможемо його дезаріалізувати на стороні сервера.


2
Це і практично, і правильно. Варто також зазначити, що більшість мов програмування робить тривіальним перетворення хеша в рядок запиту, тому починати з дії GET дуже легко.
Алуан Хаддад

1
Я люблю весну stackoverflow.com/questions/16942193/… Я не можу повірити, що це спрацювало з першої спроби: D. Довжина URL-адреси менша за 1 к, хоча нам ще потрібно повторити характеристики.
anat0lius

Потім перейдіть з GET. Для простоти. Завдяки Spring MVC ви можете домогтися того самого зіставлення з GET. Шукайте WebArgumentResolver Spring ;-)
Laiv

Base64 завищує розмір корисного навантаження приблизно на 4/3. У той час як urlencoding може зробити 3/1 для спеціальних символів, запити з переважно безпечними символами будуть зберігати однаковий розмір. Чи є якісь інші причини використовувати base64?
villasv

Не зовсім. Мені просто не подобаються (не) URL-адреси втечі. Тут перевищується корисна навантаження. Він все ще повинен відповідати максимальному розміру GET за запитом. Тому я побудував фрагмент. Користувач може спробувати. Коли я написав відповідь, я визначив пріоритет веб-семантики над деталями реалізації. Весь сенс відповіді - "продовжуйте намагатися з GET". Знайдіть свій шлях або скористайтеся будь-яким із них, яким я ділюсь з вами.
Лаїв

13

Якщо все, що у вас є, це молоток, все виглядає як цвях. Здається, проблема тут полягає в тому, що ви намагаєтесь перетворити сторінку пошуку в RESTful, і це навряд чи є загальною схемою для вирішення дизайну RESTful.

Просто перейдіть із запитом POST з параметрами, наданими користувачем, щоб отримати необхідну інформацію з бекенда. Я припускаю, що вам не потрібно робити нічого, крім пошуку, тому немає шансів вам вставити цю сторінку. Просто додайте / пошук в кінці своєї URL-адреси, щоб ви не ризикували вступити в конфлікти зі сторінкою / користувачами, яка була б RESTful


2
@LiLou_: Для цієї вимоги існують лише дві реалістичні можливості: 1. Прочитайте всі дані на передній панелі та виконайте фільтрування там. Це може бути непосильним у необхідному обсязі пам'яті. 2. Зробіть новий запит на сервер для кожної зміни критеріїв пошуку. Не має значення, чи це POST або GET-запит, але затягнута мережева затримка може бути руйнівною для користувача, що відчуває оновлення в режимі реального часу.
Барт ван Іґен Шенау

2
Я погодився б не погодитися, POST означає щось інше семантично. Я б запропонував перейти з GET і передати всі дані фільтру в параметрі запиту, якщо занадто багато параметрів, то це помилка на рівні програми.
CodeYogi

2
@CodeYogi іноді замовник не дає вам місця для обговорення. Я реалізував сторінки перегляду, схожі на Excel, з 40-50 стовпцями, кожна з яких має свій фільтр. І сортування звичайно. У будь-якому випадку, це все ще можливо з GET, але це може здатися не надто модним
Laiv July

1
@Laiv в цьому випадку потрібно серйозну дискусію, оскільки POST призначений для зміни стану сервера. Такі випадки використання не є винятковими, тому слід опікуватися без злому.
CodeYogi

2
У цих випадках документація є обов'язковою. У мене була серйозна дискусія з клієнтами щодо зручності їх застосування. Пізніше мені було доведено, що я маю рацію, оскільки кінцевий користувач погодився зі мною. Однак іноді доводиться вибирати свої битви.
Лаїв

0

Це повністю залежить від вашої моделі API: Як жодного або як дієслова.

Якщо API не існує, можливо, ви захочете отримати наступний список об'єктів:

GET: /api/v1/objects

У цьому випадку вам потрібно надіслати дані як параметри запиту. Отже, ви повинні описати свої параметри як плоский список ключових значень:

GET: /api/v1/objects

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

Деякі платформи підтримують користувацький роздільник параметрів (наприклад, Spring MVC), і ви можете конвертувати парами в об'єкт.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.