用于搜索的RESTful URL设计

时间:2008-10-16 04:51:21

标签: rest

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

设置:我有两个模型,汽车和车库,汽车可以在车库。所以我的网址看起来像:

/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的车联合怎么样?

表示搜索具有某些属性的汽车的正确方法是什么?说:给我看看所有带4扇门的蓝色轿车:

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

或应该是/汽车而不是?

使用“搜索”似乎不合适 - 什么是更好的方式/术语?它应该只是:

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

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

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

[更新]我喜欢Justin的回答,但他没有涉及多字段搜索案例:

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

或类似的东西。我们怎么去

/cars/color/blue

到多场案例?

12 个答案:

答案 0 :(得分:407)

搜索时,请使用查询字符串。这完全是RESTful:

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

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

答案 1 :(得分:111)

RESTful漂亮网址设计是关于基于结构显示资源(类似目录的结构,日期: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不同,它属于一起。

搜索

搜索查询正常,只有您的偏好,应该考虑什么。加入搜索时会出现有趣的部分(见下文)。

/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

可能的功能?

否定搜索字符串(!)
要搜索任何车辆,但 黑色红色
?color=!black,!red
color:(!black,!red)

加入搜索
在车库id 1..20中 3 门搜索红色蓝色黑色汽车 101..103 999 5 /garage[id=1-20,101-103,999,!5]/cars[color=red,blue,black;doors=3]
然后,您可以构建更复杂的搜索查询。 (请查看CSS3 attribute matching有关匹配子字符串的想法。例如,搜索包含“bar”user*=bar的用户。)

结论

无论如何,这可能是你最重要的部分,因为你可以随心所欲地做到这一点,但请记住 RESTful URI代表一个易于理解的结构,例如:类似目录的/directory/file/collection/node/item,日期/articles/{year}/{month}/{day} ..当您省略任何最后一段时,您会立即知道所得到的内容。

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

  • 无保留:a-zA-Z0-9_.-~
  • reserved:;/?:@=&$-_.+!*'(),
  • 不安全*:<>"#%{}|\^~[]`

*为什么不安全以及为什么要编码:RFC 1738 see 2.2

RFC 3986 see 2.2
尽管我之前曾说过,但这是一个常见的分界符区别,这意味着某些“是”比其他人更重要。

  • generic delimeters::/?#[]@
  • sub-delimeters:!$&'()*+,;=

更多阅读:
层次结构:see 2.3see 1.2.3
url path parameter syntax
CSS3 attribute matching
IBM: RESTful Web services - The basics
注意:RFC 1738由RFC 3986更新

答案 2 :(得分:35)

虽然路径中的参数有一些优点,但IMO有一些超重因素。

  • 网址中不允许搜索查询所需的所有字符。大多数标点符号和Unicode字符都需要进行URL编码作为查询字符串参数。我正在努力解决同样的问题。我想在URL中使用XPath,但并非所有XPath语法都与URI路径兼容。因此,对于简单路径,/cars/doors/driver/lock/combination适合在驱动程序门XML文档中找到“combination”元素。但是/car/doors[id='driver' and lock/combination='1234']并不那么友好。

  • 根据资源的某个属性过滤资源和指定资源之间存在差异。

    例如,因为

    /cars/colors返回所有汽车的所有颜色列表(返回的资源是颜色对象的集合)

    /cars/colors/red,blue,green将返回红色,蓝色或绿色的颜色对象列表,而不是汽车的集合。

    要返回汽车,路径将是

    /cars?color=red,blue,green/cars/search?color=red,blue,green

  • 路径中的参数更难以读取,因为名称/值对不与路径的其余部分隔离,而不是名称/值对。

最后一条评论。我更喜欢/garages/yyy/cars(总是复数)到/garage/yyy/cars(也许这是原始答案中的拼写错误)因为它避免改变单数和复数之间的路径。对于添加了“s”的字词,更改并不是那么糟糕,但将/person/yyy/friends更改为/people/yyy似乎很麻烦。

答案 3 :(得分:30)

为了扩展彼得的答案 - 你可以使搜索成为一流的资源:

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)

搜索资源将包含颜色,制作模型,车库状态等字段,并且可以使用XML,JSON或任何其他格式指定。与Car和Garage资源一样,您可以根据身份验证限制对搜索的访问。经常运行相同搜索的用户可以将其存储在其配置文件中,以便不需要重新创建它们。这些网址足够短,在很多情况下,它们可以通过电子邮件轻松交易。这些存储的搜索可以作为自定义RSS源的基础,等等。

当您将搜索视为资源时,可以使用搜索。

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

答案 4 :(得分:11)

贾斯汀的答案可能是要走的路,尽管在某些应用中,将特定搜索本身视为资源可能是有意义的,例如,如果您想支持已命名的已保存搜索:

/search/{searchQuery}

/search/{savedSearchName}

答案 5 :(得分:5)

这不是REST。您无法为API中的资源定义URI。资源导航必须是超文本驱动的。如果你想要漂亮的URI和大量的耦合,那就好了,但是不要把它叫做REST,因为它直接违反了RESTful架构的限制。

REST的发明者见article

答案 6 :(得分:5)

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

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

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

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

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

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

FirstStreet所有非红色车库的车辆(第3页,每页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

答案 7 :(得分:1)

虽然我喜欢贾斯汀的回答,但我觉得它更准确地代表过滤器而不是搜索。如果我想知道名字以cam开头的汽车怎么办?

我看待它的方式,您可以将其构建为处理特定资源的方式:
/汽车/ CAM *

或者,您只需将其添加到过滤器中:
/汽车/门/ 4 /名/ CAM * /颜色/红,蓝,绿

就个人而言,我更喜欢后者,但我绝不是REST的专家(仅在2周左右才第一次听说......)

答案 8 :(得分:1)

RESTful建议不要在URL / cars / search中使用动词。过滤/搜索/分页API的正确方法是通过查询参数。但是,有些情况下你必须打破常态。例如,如果要搜索多个资源,则必须使用/ search?q = query

之类的内容

您可以通过http://saipraveenblog.wordpress.com/2014/09/29/rest-api-best-practices/了解设计RESTful API的最佳做法

答案 9 :(得分:1)

另外我还建议:

library(raster)
x <- c(1:60)
y <- c(2:5)
c <- rnorm(60)
Data1 <- data.frame(x, y, c)
raster1 <- rasterFromXYZ(Data1)
plot(raster1)

此处,/cars/search/all{?color,model,year} /cars/search/by-parameters{?color,model,year} /cars/search/by-vendor{?vendor} 被视为Search资源的子资源。

答案 10 :(得分:0)

这里有很多很好的选择。你还应该考虑使用POST机身。

查询字符串非常适合您的示例,但如果您有更复杂的内容,例如任意长的项列表或布尔条件,您可能希望将帖子定义为文档,客户端通过POST发送。

这样可以更灵活地描述搜索,并避免服务器URL长度限制。

答案 11 :(得分:-3)

我的建议是:

/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