我在寻找一个可靠的方法在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的标准API,另一个Web服务调用,...
在两个例子是很简单的支持,但我也需要像字符串搜索更复杂的搜索功能,搜索前/后日期,NOT ...
这是一个常见的问题,我认为。 是否有一个库(或模式),我可以使用:
- 地图搜索指定为字符串到一个通用的标准模型的查询。 搜索格式不必是一样的我上面列出。
- 让我来映射的是标准模式,我需要使用任何技术 。
- 提供了休眠/ JPA / SQL映射支持,但是这是一个奖金;)
亲切的问候,
格伦
每当我面对这些问题,我问自己:“我将如何呈现这个用户,如果我创建一个传统的网页”? 简单的答案是,我不会介绍这些类的选项单页。 接口会过于复杂; 但我可以做的是提供允许用户在多个页面建立更多,更复杂的查询,这就是解决方案,我认为你应该在这种情况下,去的接口。
该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>
这一结果则让我们改善我们的查询。 所以刚才说,我们希望白色汽车,但不是“灰白色”车,那么我们可以得到“/汽车?颜色=白色&颜色2 =灰白色&COLOR2逻辑=不”,这可能会返回
<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门,在这种情况下歌厅/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>
同样,作为我们改进的颜色,我们可能会发现他们的只有少数几个选项,在这种情况下,我们可以提供字符串搜索,提供一个枚举搜索切换。 例如,歌厅/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个左右的城市,然后枚举他们可以是非常有帮助的。
是否有会为你做这个图书馆吗? 没有,我知道的。 大多数我见过甚至不支持超媒体控件(即你要添加的联系,并形成自己 )。 有没有可以使用的模式? 是的,我相信上面是解决这类问题的有效方式。
嗯...这是一个棘手的区域。 有在那里没有框架,这对于你的问题量身定制。 即使是ODATA @ p0wl提到有大约字段映射到域模型的方式一定的局限性。 这点之后会很奇怪。
要解决这个问题最简单的方法是接受查询作为一个字符串,然后你验证对使用AST或不管它是什么,你想要一个领域特定语言。 这可以让你在接受查询,同时还验证它的正确性是灵活的。 什么,你失去的是通过URL来描述一个更有意义的方式查询的能力。
看看第8章的宁静食谱菜谱。 它突出了我提出的解决方案之一,还建议其他方法。 选择一个基于您的客户对您的查询的表现所需的灵活性。 有你的地方可以取得平衡。
@GlennV
我不知道有直接关系,这种模式/规则,如果这是一个常见的问题(我的意思是在查询字符串逻辑运算符),但我会问设计这样的事情时,以下问题对自己说:
的问题是,的URI(作为一个整体,包括查询字符串部分)必须由服务提供商完全控制,并且客户端不能直接地耦合到URI构造逻辑,其是特定于您的问题域。
有几种方法客户端如何使用URI,以及他们如何构建它们:
- 客户端的可以通过跟随被包括或者在HTTP头中的链接“链接:<...>”页眉或实体主体(如原子或HTML链接或类似的东西)
- 客户可以通过媒体类型或其他规范定义的规则构建的URI。
引导URI施工过程中的一些众所周知的方法:
- HTML GET其中表单字段是根据编码形式RFC3986和附加到表单的action属性值所提供的URI(媒体类型的指导下);
- URI模板(相当广泛,虽然实在值得阅读,规范提供了非常有趣的功能) RFC6570
- 打开搜索查询(媒体类型的指导下)
根据上述信息,您可以选择现有的方法或设计你自己的,但在考虑简单的规则,服务必须协调的客户,他们是如何构造查询(即定义自己的规格,定制的媒体类型,或扩展现有的)。
另一件事是,你将如何URI的映射到底层实现,并有在REST方面两个非常重要的事情:
- 连接器 -其中包括HTTP + URI规范,为客户实际上只连接器的问题。
- 组件 -这是基础实现和除了你没有人关心。 这部分需要从客户完全隐藏,并且你可以选择任何有约束力的方式在这里,没有人能告诉你确切的方式,这完全取决于具体的要求(一个或多个)。
你搜索像ODATA(库链接 )?
这将解决您的查询解析的问题,你可以只查询转发到您选择的数据库。
正如前面提到的,仍然心不是一个通用的解决方案来做到这一点。 也许,最好的选择(在tleast最好的香港专业教育学院发现)是春节DATA REST( http://static.springsource.org/spring-data/rest/docs/1.1.0.M1/reference/htmlsingle/ )。 使用CrudRepository你可以像findOne,的findAll等方法,如果你扩展它,你可以添加自己的通用映射。 在例子中,我们所做的是把它扩大到有像通用查询选项:客户国家= notArgentina,为了得到不属于阿根廷的客户。 或者,例如:客户国家=像( 岛 ),以获得各界客户提供全国像“岛”(在SQL的方式)。 希望能帮助到你。