Дизайн API RESTful query з довгим списком параметрів запиту [закрито]


153

Мені потрібно розробити API RESTful query, який повертає набір об’єктів на основі кількох фільтрів. Звичайний метод HTTP для цього - GET. Єдина проблема полягає в тому, що він може мати щонайменше десяток фільтрів, і якщо ми передамо їх усі як параметри запиту, URL може отримати досить довгий (достатньо довгий, щоб блокувати якийсь брандмауер).

Зменшення кількості параметрів - це не варіант.

Однією з альтернатив, про які я міг би придумати, є використання методу POST на URI та надсилання фільтрів як частини тіла POST. Це проти того, щоб бути RESTfull (Здійснення виклику POST для запиту даних).

Хтось має кращі дизайнерські пропозиції?


2
Використовувати короткі назви параметрів (1-char тощо)?
Madbreaks

2
Це може бути не по-справжньому RESTful, але я думаю, що ви повинні бути практичними, коли мова йде про GET та POSTs. Якщо у вас є стільки змінних для надсилання, і ви не можете їх зменшити, я б розмістив їх. Мені не подобається перенавантажувати URL, але це тільки я.
Дуг Доусон

Дякую. Незважаючи на те, що це питання закрите, це саме питання, на яке мені потрібна відповідь. Я радий, що ти запитав.
Кейсі Крукстон

Відповіді:


142

Пам'ятайте, що з API REST це все питання вашої точки зору.

Два ключових поняття в API REST - це кінцеві точки та ресурси (сутності). Вільно кажучи, кінцева точка або повертає ресурси через GET, або приймає ресурси через POST та PUT тощо (або комбінацію вищезазначеного).

Прийнято, що за допомогою POST, надіслані вами дані можуть або не можуть призвести до створення нового ресурсу та пов’язаних з ним кінцевих точок (ів), які, швидше за все, не "живуть" за URL-адресою POSTed. Іншими словами, коли ви відправляєте пошту, ви надсилаєте дані кудись для обробки. Кінцева точка POST - це не місце, де зазвичай можна знайти ресурс.

Цитуючи з RFC 2616 (при цьому відсутні релевантні частини та виділені відповідні частини):

9.5 ПОСТ

Метод POST використовується для запиту, щоб сервер-джерело прийняв сутність, включену в запит, як новий підлеглий ресурс, ідентифікований URI-запитом у рядку запиту. POST розроблений таким чином, щоб дозволити єдиний метод охопити наступні функції:

  • ...
  • Надання блоку даних, таких як результат подання форми, до процесу обробки даних;
  • ...

...

Дія, виконана методом POST, може не призвести до ресурсу, який можна ідентифікувати за допомогою URI . У цьому випадку або 200 (ОК), або 204 (Без вмісту) є відповідним статусом відповіді, залежно від того, включена у відповідь суб'єкт, який описує результат .

Якщо ресурс створений на початковому сервері, відповідь ДОЛЖЕН би бути 201 (Створено) ...

Ми звикли до кінцевих точок та ресурсів, що представляють "речі" чи "дані", будь то користувач, повідомлення, книга - все, що диктує проблемний домен. Однак кінцева точка може також відкрити інший ресурс - наприклад результати пошуку.

Розглянемо наступний приклад:

GET    /books?author=AUTHOR
POST   /books
PUT    /books/ID
DELETE /books/ID

Це типовий REST CRUD. Однак що робити, якщо ми додали:

POST /books/search

    {
        "keywords": "...",
        "yearRange": {"from": 1945, "to": 2003},
        "genre": "..."
    }

У цій кінцевій точці немає нічого нерестинного. Він приймає дані (сутність) у формі органу запиту. Ці дані є критеріями пошуку - DTO, як і будь-який інший. Ця кінцева точка виробляє ресурс (сутність) у відповідь на запит: Результати пошуку . Ресурс результатів пошуку є тимчасовим, який подається негайно клієнту, без перенаправлення та без впливу інших канонічних URL-адрес.

Це все ще REST, за винятком об'єктів, які не є книгами - суб'єктом запиту є критерії пошуку книг, а суб'єктом відповіді є результати пошуку книг.


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

Особисто я б пішов BooksSearchCriteriaDTOі з BooksSearchResultsDTO.
Амір Абірі

який би був найкращий код відповіді HTTP для цього випадку POST / книги / пошук? 201 все ще застосовується?
Л. Голландія

9
201 - навпаки - це означає, що створено ресурс. Ресурс, який, як очікується, десь матиме свій унікальний URI. 201 підходить, коли POSTвикористовується для C частини CRUD. Я б пішов із звичайними старими 200, можливо, з 204 для порожніх результатів пошуку.
Амір Абірі

@AmirAbiri дуже дякую
мохамед-мхірі

84

Багато людей прийняли практику, що GET із занадто довгим або занадто складним рядком запиту (наприклад, рядки запиту не обробляють вкладені дані легко) може бути надісланий як POST, а складні / довгі дані представлені в тілі запиту.

Знайдіть специфікацію POST в специфікації HTTP. Це неймовірно широко. (Якщо ви хочете проплисти на лінійному кораблі через лазівку в REST ... використовуйте POST.)

Ви втрачаєте частину переваг семантики GET ... як автоматичні повторні спроби, тому що GET ідентичний, але якщо ви можете жити з цим, вам може бути простіше просто прийняти обробку дійсно довгих або складних запитів з POST.

(довгий відступ ... Нещодавно я виявив, що за специфікацією HTTP GET може містити тіло документа. Є один розділ, який перефразовує: "Будь-який запит може мати орган документа, за винятком перелічених у цьому розділі" ... і розділ, на який він посилається, не містить жодного списку. Я шукав і знайшов тему, де автори HTTP говорили про це, і це було навмисно, щоб маршрутизаторам та іншим не довелося розмежовувати різні повідомлення. Однак у практикуйте багато інфраструктури, що скидає тіло GET. Таким чином, ви можете отримати з фільтрами, представленими в тілі, як POST, але ви будете котити кістки.)


11
Дивіться також це питання для більш детальної дискусії про HTTP GET з тілом.
RickyA

6

Коротше кажучи: Створіть метод POST, але замініть HTTP, використовуючи метод X-HTTP-Override заголовок .

Реальний запит

POST / книги

Орган влади

{"title": "Ipsum", "year": 2017}

Заголовки

Перевірка методу X-HTTP: GET

На стороні сервера перевірте, чи існує заголовок X-HTTP-Method-Override, і прийміть його значення як метод побудови маршруту до кінцевої кінцевої точки в бекенде. Також візьміть тіло сутності як рядок запиту. З точки зору бекенда, запит став просто GET.

Таким чином ви підтримуєте дизайн у відповідності з принципами REST.

Редагувати: Я знаю, що це рішення спочатку мало на меті вирішити проблему дієслів PATCH у деяких браузерах та серверах, але воно також працює для мене з GET verb у випадку дуже довгої URL-адреси, яка є проблемою, описаною в питанні.




@jannis RFC, на який ви посилаєтеся, залишається 1,4. він не дає жодних рекомендацій щодо існуючого X-видалення та 1.5. він не перекриває існуючі технічні характеристики. ... X-чи залишиться тут ІМО.
Ян Молнар

-3

Якщо ви розвиваєтеся в Java та JAX-RS, рекомендую вам використовувати @QueryParam з @GET

У мене було те саме питання, коли мені потрібно було пройти список.

Див. Приклад:

import java.util.List;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Response;

@Path("/poc")
public class UserService {

    @GET
    @Path("/test/")
    @Produces(MediaType.APPLICATION_JSON)
    public Response test(@QueryParam("code") final List<Integer> code) {
                Integer int0 = codigo.get(0);
                Integer int1 = codigo.get(1);

        return Response.ok(new JSONObject().put("int01", int0)).build();
    }
}

Шаблон URI: “poc / test? Code = 1 & code = 2 & code = 3

@QueryParam автоматично перетворить параметр запиту "orderBy = age & orderBy = ім'я" в java.util.List.


Було б краще, якщо ви поясните свій приклад. Якою мовою програмування написано?
Алекс Андрєєв

Привіт @AleksAndreev Дякую за вашу думку Стало краще? tks
acacio.martins

Це питання стосується дизайну послуги RESTful, а не щодо впровадження. Ця відповідь не дає відповіді на запитання.
Єретична мавпа

@ user1331413 IMHO так, зараз краще. Дякую за ваші зусилля. Однак, як сказав Майк МакКаган, питання стосується концепції REST, а не реалізації
Алекс Андрєєв
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.