何时在RESTful API中使用路径参数与查询参数?


141

我想使我的RESTful API非常可预测。确定何时使用URI而不是使用查询参数对数据进行分段的最佳实践是什么?

对我来说,支持分页,排序和分组的系统参数应该位于“?”之后 但是,诸如“状态”和“区域”之类的字段或对您的收藏进行细分的其他属性呢?如果这些也要用作查询参数,那么知道何时使用路径参数的经验法则是什么?


1
类似的问题在这里回答... stackoverflow.com/questions/3198492/...
拉利特·梅赫拉

Answers:


239

RESTful API设计的最佳实践是使用路径参数来标识一个或多个特定资源,而使用查询参数来对这些资源进行排序/过滤。

这是一个例子。假设您正在为称为Car的实体实现RESTful API端点。您将像这样构造端点:

GET /cars
GET /cars/:id
POST /cars
PUT /cars/:id
DELETE/cars/:id

这样,您仅在指定要提取的资源时才使用路径参数,但这不会以任何方式对资源进行排序/过滤。

现在,假设您想在GET请求中添加按颜色过滤汽车的功能。因为color不是资源(它是资源的属性),所以您可以添加执行此操作的查询参数。您可以将查询参数添加到GET/cars请求中,如下所示:

得到 /cars?color=blue

将实现此端点,以便仅退回蓝色汽车。

就语法而言,您的URL名称应全部小写。如果您的实体名称通常是两个英文单词,则可以使用连字符来分隔单词,而不要使用驼峰式大小写。

例如 /two-words


3
谢谢您的回答,迈克。这是一个简单明了的方法。值得我投票。不过,开发人员经常还是选择“汽车/蓝色”方法,我想知道这样做的理由是什么……也许他们决定为必填字段设置路径参数,或者他们这样做是为了表明数据库由该碎片分区。
cosbor11

1
我不确定他们的理由是什么。老实说,我不同意。我认为遵循约定并保持简单最有意义。这样,您可以让您的API使用者更好地了解他们访问该功能所需的操作。
迈克(Mike)

3
/ cars?id = 1&color = blue而不是cars / 1 /呢?color = blue。您基本上是在每种情况下过滤汽车资源
mko

1
这是错误的,因为编号为1的汽车仅存在一辆,而颜色为蓝色的汽车可能很多。身份和过滤器之间有区别
paul

1
我关于使用路径参数为何如此广泛的假设是因为许多开发人员从那些对REST原理不太了解的人(尤其是Ruby on Rails)设计的框架中学到了知识
Chris Broski,

58

思考此主题的基本方法如下:

URI是一种资源标识符,可以唯一地标识资源类型的特定实例。就像生活中的所有其他事物一样,每个对象(作为某种类型的实例)都具有时不变或时态的属性集。

在上面的示例中,汽车是非常有形的物体,具有诸如make,model和VIN的属性-永不改变,以及颜色,悬架等可能随时间改变的属性。因此,如果我们使用随时间(时间)变化的属性对URI进行编码,那么对于同一个对象,我们可能会获得多个URI:

GET /cars/honda/civic/coupe/{vin}/{color=red}

数年后,如果这辆完全相同的汽车的颜色变为黑色:

GET /cars/honda/civic/coupe/{vin}/{color=black}

请注意,汽车实例本身(对象)没有改变-只是颜色改变了。具有指向同一对象实例的多个URI将迫使您创建多个URI处理程序-这不是有效的设计,当然也不直观。

因此,URI应该仅由永不改变的部分组成,并将在整个生命周期中继续唯一地标识该资源。可能更改的所有内容都应保留给查询参数,例如:

GET /cars/honda/civic/coupe/{vin}?color={black}

底线-考虑多态性。


2
有趣的范式..这是常用的设计模式吗?您能否在其文档中提供一些使用此功能的API或概述该策略的一些参考?
cosbor11

1
我喜欢写“ URI是唯一标识资源TYPE的特定实例的资源标识符”时如何强调“ TYPE”。我认为这是一个重要的区别。
jrahhali

15

在REST API中,可预测的URI不应过分担心。URI可预测性的暗示暗示了对RESTful体系结构的误解。它假定客户端应该自己构造URI,而这实际上并不是必须的。

但是,我假设您不是在创建真正的REST API,而是在创建“受REST启发”的API(例如Google Drive)。在这些情况下,经验法则是“路径参数=资源标识”和“查询参数=资源排序”。因此,问题就变成了,您可以在没有状态/地区的情况下唯一地标识您的资源吗?如果是,则可能是查询参数。如果否,则其为路径参数。

HTH。


11
我不同意,好的API应该是可预测的。RESTful或其他方式。
cosbor11 2015年

3
我认同。URI的形成应该有韵律和理由,而不是随意命名端点。当人们可以不间断地参考文档而直观地编写API客户端时,我认为您已经编写了一个不错的API。
cosbor11

2
“何时可以直观地编写API客户端而无需不断参考文档”。那就是我认为我们对REST的理解有所不同的地方……API客户端永远不需要“构建” URL。他们应该从上一个API调用的响应中选择它。如果您将网站作为类比...,请访问facebook.com,然后选择指向事件页面的链接。您不必担心Facebook事件URL是否是“可预测的”,因为您无需输入它。您是通过超媒体链接到达的。REST API也是如此。所以,让有意义的URI给你(服务器),而不是个客户端
奥利弗·麦克菲

2
添加了注释。这并不意味着URI不应遵循易于理解的模式,而仅意味着它不是RESTful API的约束。这个领域最大的问题是人们认为客户应该自己构建URL。他们不应该这样做,因为这会在客户端和服务器之间创建不应该存在的耦合。(例如,服务器随后无法更改URL而不会破坏所有客户端应用程序)。在REST API中,服务器可以根据需要更改它们。
奥利弗·麦克菲

3
+1表示使用以下单词:““路径参数=资源标识”和“查询参数=资源排序””。这真的为我清除了它。
Doug

3

一旦我设计了一个API,其主要资源是people。通常,用户会请求过滤,people因此为了防止用户/people?settlement=urban每次都调用类似的东西,我实现了/people/urban该功能,后来使我能够轻松添加/people/rural/people如果以后有任何用处,这也允许访问完整列表。简而言之,我的推理是为通用子集添加一条路径

这里

常见查询的别名

为了使普通用户对API的体验更加愉快,请考虑将条件集打包到易于访问的RESTful路径中。例如,上面最近关闭的票证查询可以打包为GET /tickets/recently_closed


1

一般来说,当资源中存在明显的“层次结构”时,我倾向于使用路径参数,例如:

/region/state/42

如果该单个资源具有状态,则可以:

/region/state/42/status

但是,如果“区域”并不是真正公开的资源的一部分,则它可能属于查询参数之一,类似于分页(如您所述)。


0

细分更加分层和“漂亮”,但可能会受到限制。

例如,如果您有一个包含三个细分的网址,则每个细分都传递不同的参数以通过品牌,型号和颜色搜索汽车:

www.example.com/search/honda/civic/blue

这是一个非常漂亮的url,更容易被最终用户记住,但是现在您受此结构的困扰。假设您要这样做,以便用户在搜索中可以搜索所有蓝色汽车或所有本田思域?查询参数解决了这个问题,因为它提供了一个键值对。这样您就可以通过:

www.example.com/search?color=blue
www.example.com/search?make=civic

现在,您可以通过其键在查询代码中引用值“ color”或“ make”。

您可以通过使用更多细分来创建一种键值结构来解决此问题,例如:

www.example.com/search/make/honda/model/civic/color/blue

希望有道理..


-2

范例网址: /rest/{keyword}

此URL是路径参数的示例。我们可以使用来获取此URL数据@PathParam

范例网址: /rest?keyword=java&limit=10

该URL是查询参数的示例。我们可以使用来获取此URL数据@Queryparam

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.