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

cos*_*r11 98 rest api-design spring-mvc restful-url restful-architecture

我想让我的RESTful API非常可预测.决定何时使用URI而不是使用查询参数来分段数据的最佳做法是什么.

对我来说,支持分页,排序和分组的系统参数在'?'之后是有道理的.但是如果像'status'和'region'这样的字段或其他属性来分割你的收藏呢?如果那些也是查询参数,那么知道何时使用路径参数的经验法则是什么?

Mik*_*ike 163

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

这是一个例子.假设您正在为名为Car的实体实现RESTful API端点.您可以像这样构建端点:

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

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

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

得到 /cars?color=blue

将实施此端点,以便仅返回蓝色汽车.

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

防爆. /two-words

  • 有趣的琐事,“这就是所谓的烤肉串” (7认同)
  • 我不确定他们的推理是什么。老实说,我不同意。我认为遵循惯例并保持简单是最有意义的。通过这样做,您可以让 API 的使用者更好地了解他们需要做什么才能访问其功能。 (4认同)
  • 错误,因为 id 为 1 的汽车只存在一个,而蓝色的汽车可能很多。有标识和过滤器的区别 (4认同)
  • 谢谢你的回答迈克.这是一个明确而简单的方法; 值得我投票.尽管如此,开发人员通常选择"汽车/蓝色"方法,我想知道他们这样做的原因是什么......也许他们决定为强制性的字段制作路径参数,或者他们可能会这样做以表明数据库由该分片分区. (2认同)
  • / cars?id = 1&color = blue而不是cars / 1 /呢?color = blue。您基本上是在每种情况下过滤汽车资源 (2认同)
  • 我的假设是,为什么使用路径参数如此普遍,是因为许多开发人员从那些没有很好地掌握 REST 原则的人(尤其是 Ruby on Rails)设计的框架中学习。 (2认同)

Kin*_*ngz 37

思考这个问题的基本方法如下:

URI是唯一标识资源TYPE的特定实例的资源标识符.与生活中的其他一切一样,每个对象(某种类型的实例)都具有时间不变或时间的属性集.

在上面的示例中,汽车是一个非常有形的物体,其具有诸如品牌,型号和VIN之类的属性 - 永不改变,颜色,悬浮等可能随时间而变化.因此,如果我们使用可能随时间(时间)变化的属性对URI进行编码,我们最终可能会为同一个对象添加多个URI:

GET /cars/honda/civic/coupe/{vin}/{color=red}
Run Code Online (Sandbox Code Playgroud)

多年以后,如果这辆同一辆车的颜色变为黑色:

GET /cars/honda/civic/coupe/{vin}/{color=black}
Run Code Online (Sandbox Code Playgroud)

请注意,汽车实例本身(对象)没有改变 - 它只是改变的颜色.让多个URI指向同一个对象实例会强制您创建多个URI处理程序 - 这不是一个有效的设计,当然不直观.

因此,URI应该只包含永不改变的部分,并将在其生命周期内继续唯一地标识该资源.应该为查询参数保留可能更改的所有内容,如下所示:

GET /cars/honda/civic/coupe/{vin}?color={black}
Run Code Online (Sandbox Code Playgroud)

底线 - 认为多态性.

  • 这是 REST-API 设计中的一个非常好的观点和规则:“URI 应该只包含永远不会改变的部分,并且在其整个生命周期中继续唯一地标识该资源” (4认同)
  • 有趣的范例..这是一个常用的设计模式吗?您是否可以在其文档中提供一些使用此API的API或一些概述此策略的参考资料? (2认同)
  • 我喜欢你在写“URI 是唯一标识资源类型的特定实例的资源标识符”时强调“类型”的方式。我认为这是一个重要的区别。 (2认同)

Oli*_*hee 12

在REST API中,您不应过度关注可预测的URI.URI可预测性的这一建议暗示了对RESTful架构的误解.它假定客户端应该自己构建URI,而这些URI本身就不应该这样.

但是,我假设您没有创建真正的REST API,而是创建一个"REST灵感"API(例如Google Drive).在这些情况下,经验法则是"路径参数=资源识别"和"查询参数=资源分类".那么,问题就变成了,您能否在没有状态/区域的情况下唯一地识别您的资源?如果是,那么也许它是一个查询参数.如果不是,那么它就是一个路径参数.

HTH.

  • 我不同意,一个好的API应该是可预测的; RESTful或其他. (10认同)
  • 我认同.应该有如何形成URI的押韵和理由,而不是任意命名端点.当人们可以直接编写API客户端而不经常引用文档时,我认为你已经编写了一个很好的API. (3认同)
  • +1用于使用以下单词:“'路径参数=资源标识'和'查询参数=资源排序'”。这真的为我清除了它。 (3认同)
  • "当人们可以直接编写API客户端而无需不断引用文档时".这就是我认为我们对REST的理解不同...... API客户端永远不需要"构建"URL.他们应该从之前的API调用的响应中选择它.如果你把一个网站作为一个类比...你去facebook.com,然后你选择一个事件页面的链接.你不在乎facebook事件URL是否是"可预测的",因为你没有输入它.你通过超媒体链接到达那里.REST api也是如此.因此,使URI对您(服务器)有意义,而不是客户端 (2认同)
  • 添加了备注.这并不意味着URI不应该遵循易于理解的模式,它只是意味着它不是RESTful API的约束.这个领域最大的问题是人们假设客户端应该自己构建URL.他们不应该,因为这会在客户端和服务器之间创建一个不存在的耦合.(例如,服务器无法在不破坏所有客户端应用程序的情况下更改URL).在REST API中,服务器可以随意更改它们. (2认同)

Jan*_*ena 11

考虑“路径”这个词——到达某个位置的方式。路径参数应该描述如何到达您感兴趣的位置/资源。这包括目录、ID、文件等。

/vehicles/cars/vehicle-id-1
Run Code Online (Sandbox Code Playgroud)

这里,vehicle-id-1是一个路径参数。

考虑“查询”这个词 - 我认为它是询问有关路径的问题,即我的路径是蓝色的,我的路径有 100 个结果吗?

/vehicles/cars/vehicle-id-1?color=blue&limit=100
Run Code Online (Sandbox Code Playgroud)

这里color=bluelimit=100是查询参数,它们帮助描述我们到达资源后应该做什么:过滤掉蓝色的,并将它们限制为 100 个结果。


web*_*ean 6

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

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

www.example.com/search/honda/civic/blue
Run Code Online (Sandbox Code Playgroud)

这是一个非常漂亮的 url,最终用户更容易记住,但现在你有点坚持这种结构。假设您想让用户在搜索中搜索所有蓝色汽车或所有本田思域?查询参数解决了这个问题,因为它提供了一个键值对。所以你可以通过:

www.example.com/search?color=blue
www.example.com/search?make=civic
Run Code Online (Sandbox Code Playgroud)

现在,您可以通过它的键来引用该值 - 在查询代码中使用“color”或“make”。

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

www.example.com/search/make/honda/model/civic/color/blue
Run Code Online (Sandbox Code Playgroud)

希望这是有道理的..


Mar*_*Gil 6

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

这里

常见查询的别名

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