我正在寻找一种合理的方法将搜索表示为RESTful url。

设置:我有两个模型,汽车和车库,汽车可以在车库。我的url是这样的:

/car/xxxx
  xxx == car id
  returns car with given id

/garage/yyy
  yyy = garage id
  returns garage with given id

Car可以独立存在(因此有/ Car),也可以存在于车库中。如何正确地表示给定车库中的所有汽车?喜欢的东西:

/garage/yyy/cars     ?

车库里的车yyy和zzz的组合呢?

用什么正确的方式来表示搜索具有特定属性的汽车?说:给我看所有四门的蓝色轿车。

/car/search?color=blue&type=sedan&doors=4

或者应该改为/cars ?

在这里使用“搜索”似乎不合适——还有什么更好的方式/术语吗?它应该是:

/cars/?color=blue&type=sedan&doors=4

搜索参数应该是PATHINFO或QUERYSTRING的一部分吗?

简而言之,我正在寻找跨模型REST url设计和搜索的指导。

[更新]我喜欢贾斯汀的答案,但他没有涵盖多领域搜索的情况:

/cars/color:blue/type:sedan/doors:4

或者类似的东西。我们如何从

/cars/color/blue

多域的情况?


当前回答

对于搜索,使用querystrings。这是完美的RESTful:

/cars?color=blue&type=sedan&doors=4

常规查询字符串的一个优点是它们是标准的、被广泛理解的,并且它们可以从form-get生成。

其他回答

这不是REST。您不能为API内的资源定义uri。资源导航必须是超文本驱动的。如果您想要漂亮的uri和大量的耦合,这是可以的,但是不要将其称为REST,因为它直接违反了RESTful体系结构的约束。

请参阅REST发明者的这篇文章。

RESTful pretty URL设计是关于基于结构(类似目录的结构,日期:articles/2005/5/13,对象及其属性,..)显示资源,斜杠/表示层次结构,使用-id代替。

层次结构

我个人更喜欢:

/garage-id/cars/car-id
/cars/car-id   #for cars not in garages

如果用户删除了/car-id部分,它将带来直观的汽车预览。用户确切地知道他在树的什么位置,他在看什么。他一看就知道车库和汽车是有关系的。与/car/id不同,/car-id也表示它属于一起。

搜索

搜索查询是可以的,因为它是,只有你的偏好,应该考虑什么。有趣的部分出现在加入搜索时(见下文)。

/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   #also possible, but & blends in with text

或者基本上任何不是斜杠的东西,如上所述。 公式:/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

可能的功能?

否定搜索字符串(!) 搜查所有车,但不包括黑车和红车 ?颜色=黑色!红色的 颜色:(黑色!红色)

加入搜索 在id 1的车库中搜索红色、蓝色或黑色的3门汽车。20或101..103或999,而不是5 /车库[id = 1 - 20101 - 103999, ! 5] /汽车[=红色、蓝色、黑色,门= 3) 然后可以构造更复杂的搜索查询。(查看CSS3属性匹配,了解匹配子字符串的思想。例如,搜索包含“bar”user*=bar的用户。)

结论

不管怎样,这对您来说可能是最重要的部分,因为您可以按照自己的想法来做,只要记住RESTful URI表示一个容易理解的结构,例如类似目录的/目录/文件、/集合/节点/项、日期/文章/{年}/{月}/{日}..当你省略最后的任何部分时,你马上就知道你得到了什么。

所以. .,所有这些字符都允许未编码:

无限制的:a-zA-Z0-9_. - ~ 通常允许编码和不允许,这两种用法是等效的。 特殊字符:$-_.+!*'(), 保留:;/ ?: @ = & 可以按照它们所代表的目的未编码地使用,否则必须对它们进行编码。 不安全的 : <>"#%{}|^~[]` 为什么不安全,为什么应该编码:RFC 1738见2.2

更多字符类请参见RFC 1738#page-20。

RFC 3986见2.2 尽管我之前说过,这里有一个常见的delimeter的区别,这意味着一些“比”其他更重要。

发电机:[] @ sub-delimeters : !$&'()*+,;=

更多阅读: 层次结构:见2.3,见1.2.3 Url路径参数语法 CSS3属性匹配 IBM: rest式Web服务——基础知识 注:RFC 1738由RFC 3986更新

对于你的情况,这里有很多好的选择。你仍然应该考虑使用POST主体。

查询字符串非常适合您的示例,但如果您有更复杂的东西,例如任意长的项目列表或布尔条件,您可能想要将post定义为一个文档,客户端通过post发送。

这允许更灵活的搜索描述,以及避免服务器URL长度限制。

Justin的答案可能是正确的,尽管在某些应用程序中,将特定的搜索视为其本身的资源可能是有意义的,比如如果你想支持命名保存的搜索:

/search/{searchQuery}

or

/search/{savedSearchName}

我的建议是:

/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而不是查询字符串的另一个优点是,您可以利用web服务器上存在的用于HTTP流量的本机缓存机制。

这里有一个页面链接,该页面描述了REST中查询字符串的害处:http://web.archive.org/web/20070815111413/http://rest.blueoxen.net/cgi-bin/wiki.pl?QueryStringsConsideredHarmful

我使用谷歌的缓存,因为正常的页面不为我工作,这里的链接以及: http://rest.blueoxen.net/cgi-bin/wiki.pl?QueryStringsConsideredHarmful