Ответ 1
Всякий раз, когда я сталкиваюсь с этими проблемами, я спрашиваю себя: "Как я могу представить это пользователю, если бы я создавал традиционную веб-страницу"? Простой ответ заключается в том, что я бы не представил такие варианты на одной странице. Интерфейс будет слишком сложным; однако я мог бы создать интерфейс, который позволил бы пользователям создавать все более сложные запросы по нескольким страницам и что решение, на которое, я думаю, вам следует пойти в этом случае.
Ограничение HATEOAS указывает, что мы должны включать в наши ответы элементы управления гиперссылками (ссылки и формы). Итак, скажем, у нас есть разбитые на страницы коллекции автомобилей /cars
с опцией поиска, так что, когда вы получаете /cars
, он возвращает что-то вроде (BTW, я использую пользовательский тип мультимедиа здесь, но формы и ссылки должны быть довольно очевидным. Сообщите мне, если это не так):
<cars href="/cars">
<car href="/cars/alpha">...</car>
<car href="/cars/beta">...</car>
<car href="/cars/gamma">...</car>
<car href="/cars/delta">...</car>
...
<next href="/cars?page=2"/>
<search-color href="/cars" method="GET">
<color type="string" cardinality="required"/>
<color-match type="enumeration" cardinality="optional" default="substring">
<option name="exact"/>
<option name="substring"/>
<option name="regexp"/>
</color-match>
<color-logic type="enumeration" cardinality="optional" default="and">
<option name="and"/>
<option name="or"/>
<option name="not"/>
</color-logic>
</search>
<search-doors href="/cars" method="GET">
<doors type="integer" cardinality="required"/>
<door-logic type="enumeration" cardinality="required" default="and">
<option name="and"/>
<option name="or"/>
<option name="not"/>
</door-logic>
</search>
</cars>
Итак, просто скажем, что мы ищем белые автомобили, мы бы GET /cars?color=white
, и мы могли бы получить что-то вроде:
<cars href="/cars?color=white">
<car href="/cars/beta">...</car>
<car href="/cars/delta">...</car>
...
<next href="/cars?color=white&page=2"/>
<search-color href="/cars?color=white" method="GET">
<color2 type="string" cardinality="required"/>
<color2-match type="enumeration" cardinality="optional" default="substring">
<option name="exact"/>
<option name="substring"/>
<option name="regexp"/>
</color2-match>
<color2-logic type="enumeration" cardinality="optional" default="and">
<option name="and"/>
<option name="or"/>
<option name="not"/>
</color2-logic>
</search>
<search-doors href="/cars?color=white" method="GET">
<doors type="integer" cardinality="required"/>
<door-logic type="enumeration" cardinality="required" default="and">
<option name="and"/>
<option name="or"/>
<option name="not"/>
</door-logic>
</search>
</cars>
В результате мы уточним наш запрос. Так что просто скажем, что нам нужны белые автомобили, но не "не совсем белые" автомобили, мы могли бы GET '/cars? Color = white & color2 = off-white & color2-logic = not', которые могли бы вернуться
<cars href="/cars?color=white&color2=off-white&color2-logic=not">
<car href="/cars/beta">...</car>
<car href="/cars/delta">...</car>
...
<next href="/cars?color=white&color2=off-white&color2-logic=not&page=2"/>
<search-color href="/cars?color=white&color2=off-white&color2-logic=not" method="GET">
<color3 type="string" cardinality="required"/>
<color3-match type="enumeration" cardinality="optional" default="substring">
<option name="exact"/>
<option name="substring"/>
<option name="regexp"/>
</color3-match>
<color3-logic type="enumeration" cardinality="optional" default="and">
<option name="and"/>
<option name="or"/>
<option name="not"/>
</color3-logic>
</search>
<search-doors href="/cars?color=white&color2=off-white&color2-logic=not" method="GET">
<doors type="integer" cardinality="required"/>
<door-logic type="enumeration" cardinality="required" default="and">
<option name="and"/>
<option name="or"/>
<option name="not"/>
</door-logic>
</search>
</cars>
Затем мы могли бы уточнить наш запрос, но дело в том, что на каждом шаге по пути элементы управления гипермедиа сообщают нам, что возможно.
Теперь, если мы подумаем о вариантах поиска для автомобилей, цвета, двери, модели и модели не являются неограниченными, поэтому мы могли бы сделать варианты более явными, предоставив перечисления. Например,
<cars href="/cars">
...
<search-doors href="/cars" method="GET">
<doors type="enumeration" cardinality="required">
<option name="2"/>
<option name="3"/>
<option name="4"/>
<option name="5"/>
</doors>
<door-logic type="enumeration" cardinality="required" default="and">
<option name="and"/>
<option name="or"/>
<option name="not"/>
</door-logic>
</search>
</cars>
Однако единственные белые автомобили, которые у нас есть, могут быть 2 и 4 двери, и в этом случае GETing /cars?color=white
может дать нам
<cars href="/cars?color=white">
...
<search-doors href="/cars?color=white" method="GET">
<doors type="enumeration" cardinality="required">
<option name="2"/>
<option name="4"/>
</doors>
<door-logic type="enumeration" cardinality="required" default="and">
<option name="and"/>
<option name="or"/>
<option name="not"/>
</door-logic>
</search>
</cars>
Аналогично, поскольку мы уточняем цвета, мы можем найти их только в нескольких вариантах, и в этом случае мы можем перейти от предоставления строкового поиска к предоставлению поиска перечисления. например, GETing /cars?color=white
может дать нам
<cars href="/cars?color=white">
...
<search-color href="/cars?color=white" method="GET">
<color2 type="enumeration" cardinality="required">
<option name="white"/>
<option name="off-white"/>
<option name="blue with white racing stripes"/>
</color2>
<color2-logic type="enumeration" cardinality="optional" default="and">
<option name="and"/>
<option name="or"/>
<option name="not"/>
</color2-logic>
</search>
...
</cars>
Вы можете сделать то же самое для других категорий поиска. Например, изначально вы не захотите перечислять все составляющие, поэтому вы бы предоставили какой-то текстовый поиск. После того, как коллекция была усовершенствована, и есть только несколько моделей, чтобы выбрать, тогда имеет смысл предоставить перечисление. Такая же логика применяется и к другим коллекциям. Например, вы не захотите перечислять все города мира, но как только вы усовершенствовали область до 10 или около того городов, то перечисление их может быть очень полезным.
Есть ли библиотека, которая сделает это за вас? Нет, о которых я знаю. Большинство из тех, что я видел, даже не поддерживают элементы управления гипермедиа (т.е. вам нужно добавить ссылки и формы). Есть ли образец, который вы можете использовать? Да, я считаю, что приведенное выше является допустимым шаблоном для решения этой проблемы.