Ian*_*lor 18 sql database api rest
我正在构建一个包含内容和可由用户定义的模式的通用API.我想为API响应添加过滤逻辑,以便用户可以查询它们存储在API中的特定对象.例如,如果用户正在存储事件对象,他们可以执行以下操作:
properties.categories包含Engineeringproperties.created_at比年龄大2016-10-02properties.address.city不是Washingtonproperties.name是Meetup我正在尝试设计过滤到API响应的查询字符串,并提出一些选项,但我不确定它的哪种语法最好...
/events?properties.name=Harry&properties.address.city.neq=Washington
Run Code Online (Sandbox Code Playgroud)
此示例仅使用嵌套对象来特定运算符(neq如图所示).这很好,因为它非常简单,易于阅读.
但是,如果事件的属性可以由用户定义,则会遇到一个问题,即address.city.neq使用普通等于运算符命名的属性与address.city使用不等于运算符命名的属性之间可能存在冲突.
示例:Stripe的API
/events?properties.name=Harry&properties.address.city+neq=Washington
Run Code Online (Sandbox Code Playgroud)
此示例与第一个示例类似,不同之处在于它使用+分隔符(相当于空格)进行操作,而不是.因为没有混淆,因为我的域中的键不能包含空格.
一个缺点是它稍微难以阅读,尽管这可以说是有争议的,因为它可能被解释为更清楚.另一个可能是解析起来稍微困难,但不是那么多.
/events?properties.name=Harry&properties.address.city=neq:Washington
Run Code Online (Sandbox Code Playgroud)
此示例与前一个示例非常相似,只是它将运算符语法移动到参数的值而不是键.这有利于消除解析查询字符串的一些复杂性.
但这是以不再能够区分检查文字字符串的相等运算符和检查字符串neq:Washington的不相等运算符为代价的Washington.
示例:Sparkpay的API
/events?filter=properties.name==Harry;properties.address.city!=Washington
Run Code Online (Sandbox Code Playgroud)
此示例使用单个顶级查询参数filter来命名所有过滤逻辑.这很好,因为您永远不必担心顶级命名空间冲突.(虽然在我的情况下,所有自定义都嵌套properties.在一起,所以这首先不是问题.)
但是,当您想要进行基本的相等过滤时,需要输入更难的查询字符串,这可能会导致必须在大多数时间检查文档.并且依赖于运算符的符号可能会导致诸如"近"或"内"或"包含"之类的非明显操作的混淆.
/events?filter=properties.name eq Harry; properties.address.city neq Washington
Run Code Online (Sandbox Code Playgroud)
此示例使用与前一个类似的顶级filter参数,但它使用单词拼写运算符而不是使用符号定义它们,并且它们之间有空格.这可能稍微更具可读性.
但这需要花费更长的URL,以及需要编码的大量空间?
示例:OData的API
/events?filter[1][key]=properties.name&filter[1][eq]=Harry&filter[2][key]=properties.address.city&filter[2][neq]=Washington
Run Code Online (Sandbox Code Playgroud)
此示例还使用顶级filter参数,但不是为模拟编程的模型创建完全自定义语法,而是使用更标准的查询字符串语法构建过滤器的对象定义.这有利于带来更多的"标准".
但它的代价是打字非常冗长,难以解析.
鉴于所有这些示例或不同的方法,哪种语法最好?理想情况下,构造查询参数很容易,因此在URL栏中玩游戏是可行的,但也不会给将来的互操作性带来问题.
我倾向于#2,因为它看起来很清晰,但也没有其他方案的一些缺点.
小智 6
我可能不会回答"哪一个最好"的问题,但我至少可以给你一些见解和其他例子来考虑.
首先,您谈论的是"带有内容的通用API和可以由用户定义的模式".
这听起来很像solr/elasticsearch,它们都是Apache Lucene的高级包装器,基本上是索引和聚合文档.
这两个采用完全不同的方法来处理其他API,我碰巧与它们一起工作.
Elasticsearch:
他们制作了完整的基于JSON的Query DSL,目前看起来像这样:
GET /_search
{
"query": {
"bool": {
"must": [
{ "match": { "title": "Search" }},
{ "match": { "content": "Elasticsearch" }}
],
"filter": [
{ "term": { "status": "published" }},
{ "range": { "publish_date": { "gte": "2015-01-01" }}}
]
}
}
}
Run Code Online (Sandbox Code Playgroud)
取自他们目前的文件.我很惊讶你实际上可以将数据放入GET中 ...它实际上看起来更好了,在早期版本中它更加层次化.
根据我的个人经验,这个DSL功能强大,但很难学习和使用流利(特别是旧版本).要实际获得一些结果,您需要的不仅仅是玩URL.从许多客户端甚至不支持GET请求中的数据这一事实开始.
SOLR:
他们将所有内容放入查询参数中,基本上看起来像这样(取自doc):
q=*:*&fq={!cache=false cost=5}inStock:true&fq={!frange l=1 u=4 cache=false cost=50}sqrt(popularity)
Run Code Online (Sandbox Code Playgroud)
使用它更直接.但这只是我的个人品味.
现在谈谈我的经历.我们在这两个之上实现了另一层,我们采用了#4号方法.实际上,我认为应该同时支持#4和#5.为什么?因为无论你选择什么,人们都会抱怨,因为无论如何你将拥有自己的"微型DSL",你可能也会为你的关键字支持更多的别名.
为什么不#2?拥有单个过滤器参数和内部查询可让您完全控制DSL.在我们制作资源半年后,我们得到了"简单"的功能请求 - 逻辑OR和括号().查询参数基本上是一个AND操作列表,逻辑上OR就像city=London OR age>25不适合那里.另一方面,括号引入嵌套到DSL结构中,这也是扁平查询字符串结构中的问题.
那些是我们偶然发现的问题,你的情况可能会有所不同.但是仍然值得考虑一下,这个API未来的期望是什么.
| 归档时间: |
|
| 查看次数: |
6345 次 |
| 最近记录: |