我在为休息服务设计网址时遇到一些困难,该休息服务可以根据分页作为一种操作处理客户请求,或者请求大于或小于运营商作为另一种类型的操作。例如:
分页:
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
我确信我错过了一些明显的东西 - 有没有人有更好的解决方案?
答案 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。
考虑您要为id
和page
:
/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 BY
和LIMIT
,此处未显示):
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