用于search的REST式URLdevise
我正在寻找一种合理的方式来将search表示为RESTfulurl。
设置:我有两个模型,汽车和车库,汽车可以在车库。 所以我的网站看起来像:
/car/xxxx xxx == car id returns car with given id /garage/yyy yyy = garage id returns garage with given id
汽车可以独立存在(因此/汽车),也可以存在车库。 什么是正确的方式来代表某车库中的所有车辆? 就像是:
/garage/yyy/cars ?
如何在车库yyy和zzz的汽车联盟?
什么是正确的方式来表示search具有某些属性的汽车? 说:给我看看所有蓝色轿车,4门:
/car/search?color=blue&type=sedan&doors=4
还是应该是/汽车呢?
“search”的使用似乎不合适 – 有什么更好的方式/术语? 它应该是:
/cars/?color=blue&type=sedan&doors=4
search参数应该是PATHINFO还是QUERYSTRING的一部分?
总之,我正在寻找一个很好的指导/教程交叉模型REST的urldevise,并进行search。
[更新]我喜欢贾斯汀的回答,但他没有涉及多领域的search案例:
/cars/color:blue/type:sedan/doors:4
或类似的东西。 我们如何去
/cars/color/blue
到多场的情况下?
为了search,使用querystrings。 这是完美的RESTful:
/cars?color=blue&type=sedan&doors=4
常规querystrings的一个好处是,他们是标准的,广泛的理解,他们可以从forms得到生成。
RESTful漂亮的URLdevise是基于一个结构(目录结构,date:articles / 2005/5/13,对象及其属性等)来显示资源,斜线/
表示分层结构,使用-id
代替。
层次结构
我会个人喜欢:
/garage-id/cars/car-id /cars/car-id #for cars not in garages
如果用户删除了/car-id
部分,它会使cars
预览 – 直观。 用户完全知道他在树中的位置,他在看什么。 他从第一眼就知道,车库和汽车是有关系的。 /car-id
也表示它不属于/car/id
。
search
searchquery是可以的 ,只有你的偏好,应该考虑的是什么。 有趣的部分来自joinsearch(见下文)。
/cars?color=blue;type=sedan #most prefered by me /cars;color-blue+doors-4+type-sedan #looks good when using car-id /cars?color=blue&doors=4&type=sedan #I don't recommend using &*
或者基本上什么都不是如上所述的斜线。
公式: /cars[?;]color[=-:]blue[,;+&]
,*虽然我不会使用&
符号,因为它从文本乍看起来是无法识别的。
** 你知道在URI中传递JSON对象是RESTful吗? **
选项列表
/cars?color=black,blue,red;doors=3,5;type=sedan #most prefered by me /cars?color:black:blue:red;doors:3:5;type:sedan /cars?color(black,blue,red);doors(3,5);type(sedan) #does not look bad at all /cars?color:(black,blue,red);doors:(3,5);type:sedan #little difference
可能的function?
取消searchstring(!)
search任何汽车,但不是 黑色和红色 :
?color=!black,!red
color:(!black,!red)
joinsearch
在车库ID为1..20或101..103或999而不是 5 /garage[id=1-20,101-103,999,!5]/cars[color=red,blue,black;doors=3]
然后,您可以构build更复杂的search查询。 (查看CSS3属性匹配的匹配子串的想法,例如search包含“bar” user*=bar
。)
结论
无论如何,这可能是对你来说最重要的部分,因为你可以做到这一点,不pipe你喜欢什么,只要记住, RESTful URI表示一个容易理解的结构,例如类似目录的/directory/file
, /collection/node/item
,date/articles/{year}/{month}/{day}
..而当你忽略任何最后一段,你立刻就知道你得到了什么。
所以..所有这些字符都可以不编码 :
- 毫无保留:
a-zA-Z0-9_.-~
- 保留:
;/?:@=&$-_.+!*'(),
- 不安全*:
<>"#%{}|\^~[]`
*为什么不安全,为什么要编码: RFC 1738见2.2
RFC 3986见2.2
尽pipe我之前说过,但这是一个常见的区别,也就是说有些“比”更重要。
- 通用的delimeters::
:/?#[]@
- sub-delimeters:
!$&'()*+,;=
,;!$&'()*+,;=
更多阅读:
层次结构: 见2.3 , 见1.2.3
urlpath参数语法
CSS3属性匹配
IBM:REST风格的Web服务 – 基础
注意:RFC 1738由RFC 3986更新
虽然在path上有参数有一些优点,但是IMO有一些超标的因素。
-
search查询所需的所有字符都不能在url中使用。 大多数标点符号和Unicode字符需要被URL编码为查询string参数。 我正在摔跤相同的问题。 我想在URL中使用XPath,但并非所有XPath语法都与URIpath兼容。 因此,对于简单path,
/cars/doors/driver/lock/combination
将适合于在驱动程序的门XML文档中find“combination
”元素。 但是/car/doors[id='driver' and lock/combination='1234']
并不那么友好。 -
根据其中一个属性过滤资源并指定资源是有区别的。
例如,因为
/cars/colors
将返回所有车辆的所有颜色列表(返回的资源是颜色对象的集合)/cars/colors/red,blue,green
会返回一个红色,蓝色或绿色的颜色对象列表,而不是汽车的集合。返回汽车,path将是
/cars?color=red,blue,green
或/cars/search?color=red,blue,green
-
path中的参数更难以阅读,因为名称/值对与path的其余部分(不是名称/值对)不是隔离的。
最后一个评论。 我更喜欢/garages/yyy/cars
(总是复数)to /garage/yyy/cars
(也许这是原始答案中的一个错字),因为它避免了改变单数和复数之间的path。 对于添加了“s”的单词,改变并不是那么糟糕,但是改变/person/yyy/friends
到/people/yyy
似乎很麻烦。
为了扩大彼得的答案 – 你可以使search一stream的资源:
POST /searches # create a new search GET /searches # list all searches (admin) GET /searches/{id} # show the results of a previously-run search DELETE /searches/{id} # delete a search (admin)
search资源将包含颜色,模型,保存状态等字段,可以用XML,JSON或其他格式指定。 像汽车和车库资源一样,您可以根据身份validation限制对search的访问。 经常运行相同search的用户可以将其存储在他们的configuration文件中,这样他们就不需要重新创build。 url很短,在很多情况下可以通过电子邮件轻松交易。 这些存储的search可以作为自定义RSS源的基础,等等。
当您将其视为资源时,使用search有很多可能性。
这个想法在Railscast中有更详细的解释。
Justin的答案可能是要走的路,尽pipe在某些应用程序中,将特定search视为资源本身是合理的,例如,如果您想要支持命名的保存search:
/search/{searchQuery}
要么
/search/{savedSearchName}
这不是REST。 您不能在API中定义资源的URI。 资源导航必须是超文本驱动的。 如果你需要漂亮的URI和大量的耦合,那就好,但是不要把它叫做REST,因为它直接违反了RESTful体系结构的限制。
请参阅REST发明人的这篇文章 。
我使用两种方法来执行search。
1)最简单的情况下,查询相关的元素,并进行导航。
/cars?q.garage.id.eq=1
这意味着,查询车库ID等于1的汽车。
也可以创build更复杂的search:
/cars?q.garage.street.eq=FirstStreet&q.color.ne=red&offset=300&max=100
FirstStreet车库中的所有车辆不是红色的(第3页,每页100个元素)。
2)复杂的查询被认为是创build并可以恢复的常规资源。
POST /searches => Create GET /searches/1 => Recover search GET /searches/1?offset=300&max=100 => pagination in search
用于search创build的POST正文如下所示:
{ "$class":"test.Car", "$q":{ "$eq" : { "color" : "red" }, "garage" : { "$ne" : { "street" : "FirstStreet" } } } }
它基于Grails(标准DSL): http : //grails.org/doc/2.4.3/ref/Domain%20Classes/createCriteria.html
虽然我喜欢贾斯汀的回应,但我觉得它更准确地代表了filter而不是search。 如果我想知道名称以cam开头的汽车怎么办?
我看到它的方式,可以将其构build为处理特定资源的方式:
/汽车/ CAM *
或者,您可以简单地将其添加到filter中:
/汽车/门/ 4 /名/ CAM * /颜色/红,蓝,绿
就我个人而言,我更喜欢后者,但我绝不是REST的专家(仅在2周前才听说过…)
RESTful不build议在URL / cars / search中使用动词不安宁。 筛选/search/分页您的API的正确方法是通过查询参数。 但是,有些情况下,你必须打破规范。 例如,如果您要跨多个资源进行search,则必须使用/ search?q = query之类的内容
您可以通过http://saipraveenblog.wordpress.com/2014/09/29/rest-api-best-practices/了解deviseRESTful API的最佳实践
另外我还build议:
/cars/search/all{?color,model,year} /cars/search/by-parameters{?color,model,year} /cars/search/by-vendor{?vendor}
在这里, Search
被认为是Cars
资源的子资源。
这里有很多很好的select。 你仍然应该考虑使用POST正文。
查询string对于您的示例来说是完美的,但是如果您有更复杂的内容,例如任意长的项目列表或布尔条件,则可能需要将post定义为文档,即客户端通过POST进行发送。
这样可以更灵活地描述search,并避免服务器URL长度限制。
我的build议是这样的:
/garages Returns list of garages (think JSON array here) /garages/yyy Returns specific garage /garage/yyy/cars Returns list of cars in garage /garages/cars Returns list of all cars in all garages (may not be practical of course) /cars Returns list of all cars /cars/xxx Returns specific car /cars/colors Returns lists of all posible colors for cars /cars/colors/red,blue,green Returns list of cars of the specific colors (yes commas are allowed :) )
编辑:
/cars/colors/red,blue,green/doors/2 Returns list of all red,blue, and green cars with 2 doors. /cars/type/hatchback,coupe/colors/red,blue,green/ Same idea as the above but a lil more intuitive. /cars/colors/red,blue,green/doors/two-door,four-door All cars that are red, blue, green and have either two or four doors.
希望这给你的想法。 从本质上来说,您的Rest API应该很容易被发现,并且可以让您浏览您的数据。 使用URL而不是查询string的另一个优点是,您可以利用Web服务器上存在的本机caching机制来处理HTTP通信。
下面是一个描述REST查询string的恶意页面的链接: http ://web.archive.org/web/20070815111413/http://rest.blueoxen.net/cgi-bin/wiki.pl? QueryStringsConsideredHarmful
我使用了Google的caching,因为正常的页面并不适合我这里的链接: http : //rest.blueoxen.net/cgi-bin/wiki.pl?QueryStringsConsideredHarmful