REST和复杂的搜索查询

Gle*_*nnV 14 java rest search

我正在寻找一种在REST API中建模搜索查询的强大方法.

在我的api中,您可以使用查询参数在资源的URI中指定搜索条件.

例如:

/cars?search=color,blue;AND;doors,4 --> Returns a list of blue cars with 4 doors

/cars?search=color,blue;OR;doors,4 --> Returns a list of cars that are blue or have 4 doors

在服务器端,搜索字符串映射到所需的基础技术.根据其余资源,这可以是SQL查询,Hibernate Criteria api,另一个Web服务调用,......

这两个例子很简单,但我还需要更复杂的搜索功能,如子字符串搜索,日期之前/之后搜索,NOT,...

这是我认为的常见问题.是否有我可以使用的库(或模式):

  • 将指定为字符串的搜索查询映射到通用Criteria模型.搜索格式不必与上面列出的相同.
  • 允许我将Criteria模型映射到我需要使用的任何技术.
  • 为Hibernate/JPA/SQL提供映射支持,但这是一个奖励;)

亲切的问候,

格伦

Tom*_*ard 5

每当我遇到这些问题时,我会问自己"如果我正在创建传统网页,我将如何向用户展示"?简单的答案是我不会在一个页面中提供这些选项.界面太复杂了; 但我能做的是提供一个界面,允许用户在多个页面上构建越来越复杂的查询,这是我认为你应该在这种情况下应该采用的解决方案.

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>
Run Code Online (Sandbox Code Playgroud)

所以,只要说我们搜索白色汽车,我们就会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>
Run Code Online (Sandbox Code Playgroud)

然后,这个结果让我们改进我们的查询.所以只是说我们想要白色车而不是"灰白色"车,我们可以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>
Run Code Online (Sandbox Code Playgroud)

然后我们可以进一步优化我们的查询,但重点是在整个过程中的每一步,超媒体控件告诉我们什么是可能的.

现在,如果我们考虑汽车的搜索选项,颜色,门,品牌和模型都不是无限制的,所以我们可以通过提供枚举来使选项更加明确.例如

<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>
Run Code Online (Sandbox Code Playgroud)

然而,我们唯一的白色车可能是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>
Run Code Online (Sandbox Code Playgroud)

类似地,当我们改进颜色时,我们可能会发现它们只有几个选项,在这种情况下我们可以从提供字符串搜索切换到提供枚举搜索.例如,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>
Run Code Online (Sandbox Code Playgroud)

您可以对其他搜索类别执行相同操作.例如,最初你不想枚举所有的品牌,所以你会提供某种文字搜索.一旦集合被细化,并且只有几个模型可供选择,那么提供枚举是有意义的.同样的逻辑适用于其他集合.例如,你不想列举世界上所有的城市,但是一旦你将这个区域精炼到10个左右的城市,那么枚举它们会非常有帮助.

有没有一个图书馆会为你做这个?我不知道.我见过的大多数人甚至不支持超媒体控件(即你必须自己添加链接和表单).你有可以使用的模式吗?是的,我相信以上是解决此类问题的有效模式.