每当我遇到这些问题时,我都会问自己“如果我正在创建一个传统的网页,我将如何向用户展示这个”?简单的答案是我不会在一个页面中呈现这些选项。界面过于复杂;但是我可以做的是提供一个界面,允许用户在多个页面上构建越来越复杂的查询,这就是我认为在这种情况下应该采用的解决方案。
HATEOAS 约束规定我们必须在响应中包含超媒体控件(链接和表单)。所以假设我们有一个/cars
带有搜索选项的分页汽车集合,这样当你得到/cars
它时会返回类似(顺便说一句,我在这里使用自定义媒体类型,但表单和链接应该非常明显。让我知道是否不是):
<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>
所以只要说我们搜索白色汽车,我们会得到/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 个左右的城市,那么枚举它们会很有帮助。
有图书馆可以为你做这件事吗?据我所知没有。我见过的大多数甚至不支持超媒体控件(即,您必须自己添加链接和表单)。有没有可以使用的模式?是的,我相信以上是解决此类问题的有效模式。