RESTful API路由设计:嵌套与非嵌套

RESTful API路由设计:嵌套与非嵌套,rest,restful-url,api-design,nested-resources,nested-routes,Rest,Restful Url,Api Design,Nested Resources,Nested Routes,我的问题是关于为API目的构建URL时嵌套资源的优势。考虑以下两种访问雇员资源的替代方案: /api/employees?department=1 # flat Vs. /api/departments/1/employees # nested 现在考虑开发通用库以从API访问REST资源的任务。如果所有路由都是平坦的,那么这样的REST包装器库只需要知道正在访问的资源的名称: store.query('employees', {department_id:1}) =>

我的问题是关于为API目的构建URL时嵌套资源的优势。考虑以下两种访问雇员资源的替代方案:

/api/employees?department=1   # flat

Vs.

/api/departments/1/employees  # nested

现在考虑开发通用库以从API访问REST资源的任务。如果所有路由都是平坦的,那么这样的REST包装器库只需要知道正在访问的资源的名称:

store.query('employees', {department_id:1})   =>   /api/employees?department=1
然而,如果我们要支持嵌套路由,这个包装器需要知道关于嵌套了哪些模型以及在哪些其他资源下的额外信息,以便知道如何构建URL来引用这样的模型。考虑到并非所有模型都嵌套在同一父资源下,甚至有些模型根本不会嵌套,REST包装器库需要某种配置来描述所有这些额外的知识,否则就不需要这些知识

因此,我的问题是:

  • API中嵌套的资源路由有什么真正的优势吗?(这并不意味着最终用户会使用它,因此从更漂亮的URL中获益较少)

  • 嵌套方法是否真的比平面方法更好,超越了美学,从而证明为支持资源URL构建中缺乏一致性而引入的额外工作和复杂性是合理的

另见:

更新:重要澄清

我从一些评论和回答中意识到,我对一个方面不够清楚:我不反对使用URL来处理单个资源,如
/employees/5
/departments/1
。我不认为这是嵌套的。< /P> 当我说嵌套资源时,我指的是像
/departments/1/employees
这样的URL,其中一个资源总是在另一个资源的上下文中寻址。主要问题是,对于URL构建,通用库需要知道额外的内容,比如“员工嵌套在部门下”,但“分支机构不嵌套在任何东西下”。如果所有资源都可以通过REST方式进行处理,但是以一种简单的方式,那么知道如何处理它们就更简单、更可预测了

仔细想想,在数据库中,您不需要知道额外的信息,就可以知道如何处理对象集合(例如RDMS中的表)。根据我的经验,您总是将员工集合称为
员工
,而不是
部门/5/员工

: 问题1。由于关系模型,因此更易于使用,难以实现
问题2。当涉及到权限和其他潜在检查时,Nested会更好,您可以在下一个级别之前执行这些检查

如果您想再下一个级别,会发生什么

/api/addresses?部门ID=1&employeeId=2&addressId=3

vs

/api/departments/1/employees/2/address/3

地址端点突然因为参数而变得臃肿

另外,如果您查看的是RESTful API,那么RESTful API就意味着可以通过链接发现。例如,从顶层,比如/api/version(/1),您会发现有一个指向部门的链接。以下是在HAL浏览器这样的工具中的外观:

"api:department-query": {
  "href": "http://apiname:port/api/departments?pageNumber={pageNumber}&pageSize={pageSize}&sort={sort}"
},
"api:department-by-id": {
  "href": "http://apiname:port/api/departments?departmentId={departmentId}"
}
(要么是一个查询,最终可能以分页的方式列出所有这些信息,要么是一个参数化链接,如果您知道id,该链接将直接指向特定的部门)


这里的优点是,客户端只需要知道关系(链接)名称,而服务器则可以自由更改关系(和资源)url。

基于模型和安全性,我会投票支持第二种解决方案

部门位于路径中,不必位于有效负载中,无论是读还是写


如果要更改员工的部门,可以将部门ID包括在有效负载中,或通过单独的端点(使用单独的授权)/员工/{ID}。

旧帖子,但对我来说不是令人满意的答案

这取决于你的API。如果您的数据是分层的,并且不需要访问资源而不通过其父级对其进行筛选,那么嵌套是可以的(也不需要嵌套)

如果您的ID很长(GUID),层次结构很深,或者您需要访问任何资源而不通过其父级进行过滤,那么不嵌套是一个不错的选择

尽量有一个统一的接口,而不是有许多方法来访问同一资源


尝试这个链接可以更好地解释这一点:

我认为RESTAPI是访问资源的一种方式,访问资源的方式应该尽可能简单。选择对您的应用程序更有意义的选项。我更喜欢您列出的第一个选项,因为它最有意义(也是最常见的)。我将使用嵌套的RESTAPI URL深入研究资源(即/employees/{uid}或/departments/{uid}。DPT和员工之间似乎存在双向关系。可能还有一个API公开DPT->employee fetching。即/departments?user.name=Ernesto。当然,这一切都取决于您如何构建后端Lucas Crawford:请参阅我上面关于
/employees/{uid}等URL的说明
。这些不是我所关心的,因为它们不属于嵌套资源的定义。URI作为一个整体是指向某个资源的指针,包括任何路径、矩阵或查询参数。您可能认为URI是(中介)使用的键缓存以确定表示是否可用于该键。URI本身并不传递任何父子关系。因此,像
/api/companys/123/users/456
这样的URI不一定表示用户是公司的子资源。您可以将系统设计为完全这样做,但客户端不应该这样做依赖于这样的知识!相反,使用链接关系来提示clinets关于语义上下文的信息谢谢你的回答。下面再问一下:平面版本到底有什么问题