Итак, мне нужно создать API запросов RESTful, который возвращает набор объектов на основе нескольких фильтров. Обычный HTTP-метод для этого - GET. Единственная проблема заключается в том, что у нее может быть как минимум дюжина фильтров, и если мы передадим все из них в качестве параметров запроса, URL-адрес может стать довольно длинным (достаточно долго, чтобы блокироваться некоторым брандмауэром).
Уменьшение количества параметров не является вариантом.
Один из вариантов, о котором я мог думать, - использовать метод POST в URI и отправлять фильтры как часть тела POST. Это против RESTfull (создание запроса POST для запроса данных).
У кого-нибудь есть лучшие дизайнерские предложения?
Спасибо
Многие люди согласились с тем, что GET с слишком длинной или слишком сложной строкой запроса (например, строки запроса не обрабатывают вложенные данные легко) может быть отправлено как POST вместо этого, причем представленные сложные/длинные данные в теле запроса.
Посмотрите спецификацию для POST в спецификации HTTP. Он невероятно широк. (Если вы хотите отплыть линкор через лазейку в REST... используйте POST.)
Вы теряете некоторые преимущества семантики GET... например, автоматические повторы, потому что GET является идемпотентным, но если вы можете жить с ним, может быть проще просто принять обработку длинных или сложных запросов с помощью POST.
(lol long digression... Недавно я обнаружил, что по спецификации HTTP GET может содержать тело документа. Там один раздел, который говорит, перефразируя: "Любой запрос может иметь тело документа, кроме тех, которые перечислены в этом разделе"... и раздел, на который он ссылается, не отображает список. Я искал и нашел поток, в котором об этом говорили авторы HTTP, и это было намеренно, так что маршрутизаторам и таким не пришлось бы различать разные сообщения. Тем не менее, на практике многие объекты инфраструктуры бросают тело GET. Таким образом, вы можете ПОЛУЧИТЬ с фильтрами, представленными в теле, например, POST, но вы будете катать кости.)
Помните, что с помощью REST API все это касается вашей точки зрения.
Двумя ключевыми понятиями в REST API являются конечные точки и ресурсы (сущности). Понятно, что конечная точка либо возвращает ресурсы через GET, либо принимает ресурсы через POST и PUT и т.д. (Или комбинацию выше).
Принимается, что с помощью POST отправленные вами данные могут или не могут привести к созданию нового ресурса и связанных с ним конечных точек, которые, скорее всего, не будут "жить" под POSTed url. Другими словами, когда вы отправляете POST, вы отправляете данные для обработки. Конечная точка POST не находится там, где обычно может быть найден ресурс.
Цитата из RFC 2616 (с несоответствующими деталями опущены и выделены соответствующие части):
9.5 POST
Метод POST используется для запроса, чтобы исходный сервер принял объект, заключенный в запрос в качестве нового подчиненного ресурса идентифицированных Request-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, за исключением того, что сущности не являются книгами - объект запроса является критерием поиска книг, а объект ответа - результаты поиска в книгах.
BooksSearchCriteriaDTO
и BooksSearchResultsDTO
.
Вкратце: сделайте POST, но переопределите HTTP-метод, используя заголовок X-HTTP-Method-Override.
Реальный запрос
POST/books
Тело сущности
{ "title": "Ipsum", "год": 2017 год }
Заголовки
X-HTTP-метод-переопределение: GET
На стороне сервера проверьте, существует ли заголовок X-HTTP-Method-Override, а затем берет его значение как способ построения маршрута к конечной конечной точке в бэкэнд. Кроме того, возьмите тело объекта как строку запроса. С обратной стороны запрос стал просто GET.
Таким образом, вы держите дизайн в гармонии с принципами REST.
Изменить: Я знаю, что это решение изначально предназначалось для решения проблемы глагола PATCH в некоторых браузерах и серверах, но оно также работает для меня с глаголом GET в случае очень длинного URL-адреса, который является проблемой описанных в вопросе.