我正在寻找一种合理的方法将搜索表示为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

多域的情况?


当前回答

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

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

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

其他回答

扩展Peter的回答——你可以让搜索成为一流的资源:

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)

The Search resource would have fields for color, make model, garaged status, etc and could be specified in XML, JSON, or any other format. Like the Car and Garage resource, you could restrict access to Searches based on authentication. Users who frequently run the same Searches can store them in their profiles so that they don't need to be re-created. The URLs will be short enough that in many cases they can be easily traded via email. These stored Searches can be the basis of custom RSS feeds, and so on.

当您将搜索视为资源时,有许多使用搜索的可能性。

这个想法在Railscast中有更详细的解释。

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更新

我使用两种方法来实现搜索。

1)最简单的情况,用于查询相关元素,并用于导航。

    /cars?q.garage.id.eq=1

这意味着,查询车库ID等于1的汽车。

也可以创建更复杂的搜索:

    /cars?q.garage.street.eq=FirstStreet&q.color.ne=red&offset=300&max=100

FirstStreet所有车库中不是红色的汽车(第三页,每页100个元素)。

2)复杂查询被认为是常规资源,可以被创建和恢复。

    POST /searches  => Create
    GET  /searches/1  => Recover search
    GET  /searches/1?offset=300&max=100  => pagination in search

创建搜索的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

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

/search/{searchQuery}

or

/search/{savedSearchName}

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

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

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