REST URL设计适用于大于,小于操作

时间:2011-01-06 11:10:10

标签: api url rest

我在为休息服务设计网址时遇到一些困难,该休息服务可以根据分页作为一种操作处理客户请求,或者请求大于或小于运营商作为另一种类型的操作。例如:

分页:

GET /customers/0/100

这将为第0页提供100个客户。

大于/小于:

我还需要一个URL设计来获取id大于n的客户(例如716)。你如何在网址中加入“大于”或“小于”。我必须记住字符“>”和“<”在网址中是非法的。我认为这个网址设计看起来很奇怪:

GET /customers/greaterthan/716
GET /customers/lessthan/716

我不能使用与上面指定的分页模式冲突的范围,并且在任何情况下都不是一个很好的解决方案,例如:

GET /customers/716/999999999999
GET /customers/0/716

我确信我错过了一些明显的东西 - 有没有人有更好的解决方案?

11 个答案:

答案 0 :(得分:30)

分页 greaterthan lessthan ,听起来像查询参数,因为您使用这些参数查询资源。所以你应该这样做:

/ customers?page = 1 ,或
/ customers?page = 1& gt = 716 ,或
/ customers?page = 1& gt = 716& lt = 819

您甚至可以限制页面大小:

/ customers?page = 1& gt = 716& lt = 819& maxpagesize = 100

其中 gt 代表大于(与xml-escaping相同), lt 代表小于。

答案 1 :(得分:16)

如果您有多个参数并需要为每个参数应用一些条件,我建议您将JSON对象传递给params。

考虑您要为idpage

做一个条件
/customers?id={"lt": 100, "gt": 30}&page={"start": 1, "size": 10}

它表示我希望 1和小于 100且大于 30的客户>页码为10。

现在,如果您想为其他参数应用其他条件,您可以通过以下方式完成:

/customers?id={"lt": 100, "gt": 30}&children={"lt": 5, "gt": 2}&page={"start": 1, "size": 10}

此查询表示客户ID 小于 100且大于 30,小孩小于 5且 页码 1大于 2 页面大小为10。

我强烈建议您阅读有关设计RESTful API的文档:http://blog.luisrei.com/articles/rest.html

答案 2 :(得分:7)

REST是一种架构风格,不应视为特定于HTTP。 URI的模式不是使架构RESTful的原因。

话虽如此,你可能想要制作你的URI,以便这些查询作为字符串末尾的查询参数,例如。

/customers?min=0&max=76

答案 3 :(得分:7)

@Julio Faerman:

  

嗯,当你得到多个参数时,问题就开始了。想象一下“查看字符串为”年龄超过18且年龄小于60但超过2个孩子的客户“。

您可以定义您喜欢的任何查询参数,例如:

/customers?min-age=19&max-age=59&min-children=3

在我的示例中,min和max是整数并且是包含的。如果您愿意,可以更改。请记住,URI中的任何内容都是资源标识符的一部分。我的个人观点是?之后的事情等同于SQL查询的WHERE部分中的条款(加上ORDER BYLIMIT,此处未显示):

SELECT * FROM customers WHERE age>=19 AND age<=59 AND children>=3

修改
您可以允许min-max-(可能>)作为参数名称的最后一个字符,而不是<!前缀,而不是min-age您有一个名为age>的参数,当与查询字符串中的值结合使用时,最终看起来像age>=19 :-)
显然,当比较中有等号时,你只能使用这个技巧。

答案 4 :(得分:2)

我们假设您要获取服务器日志,并假设您的数据如下所示:

{
    "protocol": "http",
    "host": "example.domain.com",
    "path": "/apis/classified/server/logs",
    "method": "GET",
    "ip": "::ffff:127.0.0.1",
    "time": 1483066346338,
    "usingTime": 12,
    "status": 200,
    "headers": {
        "user-agent": "Mozilla/5.0 Chrome"
    }
}

你想以这种方式查询,其中

  • protocol等于'http'
  • host等于'example.domain.com',或者不等于'example.domain.me'
  • path等于'/apis/classified/server/logs',或者喜欢/*classified\/server*/
  • method等于'DELETE'或不等于'GET'['POST', 'PUT', 'DELETE']
  • ip等于'127.0.0.1',或者不等于'127.0.0.1'
  • usingTime大于3500,或大于或等于1500且小于或等于3500
  • status等于404,或者不等于200,或者大于或等于400且小于500。
  • headers.user-agent喜欢/*chrome*/i

这里的路线是这样的:

  • /apis/classified/server/logs?path=/apis/classfied
  • /apis/classified/server/logs?path.regex=*classfied*
  • /apis/classified/server/logs?method.ne=GET
  • /apis/classified/server/logs?method=POST&method=PATCH&method=PUT
  • /apis/classified/server/logs?usingTime.gte=1500&usingTime.lte=2500
  • /apis/classified/server/logs?headers.user-agent.regex=*chrome*

如果您使用express.js作为服务器,您的req.query将结构如下:

  • {"path": "/apis/classfied"}
  • {"path": {"regex": "*classfied*"}}
  • {"method": "DELETE"}
  • {"method": ["GET","POST","PUT"]}
  • {"usingTime": {"gte": "1500","lte": "2500"}}(lte:小于或等于)
  • {"status": {"ne": "200"}}}(ne:不等于)
  • {"path": {"regex": "*classfied*"}}
  • {"headers": {"user-agent": {"regex": "*chrome*", "flag": "i"}}}

你将使用很多if-else来构成你的mongoose查询方法,或者可能是SQL字符串。

答案 5 :(得分:1)

我会将它作为范围实现,如果任何一方打开,就不要填充它。

GET /customers/16-
GET /customers/-716

请求所有客户时,请勿添加全部,只需将其留空

GET /customers

或者,当您需要时 - 在您的号码/代码中签名,请使用:

GET /customers/16/
GET /customers//716
GET /customers/16/716

如果它们是数字的一部分,您可以转义正斜杠。

答案 6 :(得分:0)

警告:请阅读以下免责声明

我不知道这个排队是否与c#有关。但是如果你在服务器端使用linq进行查询,我还有另一个建议:

GET /customers?filter=CustomerNo>=16 AND CustomerNo<=716

然后,在服务器端:

using System.Linq.Dynamic;

var filteredCustomers = myCustomerTable.Where(filter);

我认为这应该是所有人中最灵活的解决方案。

警告于2017年1月19日添加 我刚才注意到Dynamic Linq存在代码注入漏洞。上面的示例打开了客户端可以在服务器上启动代码执行的可能性。

答案 7 :(得分:0)

一些基于REST的标准提供了解决此问题的适当方法。例如,https://www.hl7.org/fhir/stu3/search.html

你的问题可以这样解决: GET /customers?id=ge500&id=lt1000

此外,OData与任何行业标准相比都具有更强的互操作性。它提出了这种风格:GET /customers?$filter=id ge 500 and id lt 1000

答案 8 :(得分:0)

这就是我一直在做的事情。

假设您有一个 age 字段,该字段是一个数字。

这是网址的样子
等于:/ filter / age = 5
大于:/ filter / age [gt] = 5
大于等于:/ filter / age [gte] = 5
小于:/ filter / age [lt] = 5
小于等于:/ filter / age [lte] = 5
不等于:/ filter / age [ne] = 5

然后,当我将这些参数传递给后端时,我有一个脚本,可以将密钥解析出来,并根据年龄将其转换为正确的过滤器[INSERT_OPERATOR_HERE]

答案 9 :(得分:0)

我建议使用查询字符串。

我建议使用以下模板之一:

?amount=~gt~100&age=~gt~16

?amount=gt100&age=gt16

?amount=gt 100&age=gt 16

?amount=greater_than(1)&age=less_than(69)

答案 10 :(得分:-1)

我会带

 GET /customers/greaterthan=16;lessthan=716/

因为订单并不重要。你甚至可以在上面分页:

 GET /customers/greaterthan=16;lessthan=716/page/10

或者(使用适当的请求路由器):

 GET /customers/16-716/page/10

没有“过滤器”:

 GET /customers/all/page/10