RESTful API 路由设计:嵌套与非嵌套
RESTful API routes design: nested vs. non-nested
我的问题是关于在为 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
。我不认为这是嵌套的。
当我说嵌套资源时,我指的是像 /departments/1/employees
这样的 URL,其中一个资源总是在另一个资源的上下文中寻址。主要问题是 为了 URL 构建,通用库需要知道额外的东西 ,例如 "employees are nested under departments" 但 "branches are not nested under anything"。如果所有资源都可以 RESTfully 方式寻址,但以平面方式寻址,那么知道如何寻址它们会更简单、更准确table。
仔细想想,在数据库中,您不需要知道额外的信息就可以知道如何处理一组对象(例如 RDMS 中的 table)。您总是将员工集合称为 employees
,而不是 departments/5/employees
。
根据我的经验:
Q1。由于关系模型,更易于使用,难以实现
Q2。在权限和其他潜在检查方面,嵌套更好,您可以在降级之前进行这些检查
如果您想向下钻取更多级别会怎样?
/api/addresses?departmentId=1&employeeId=2&addressId=3
对
/api/departments/1/employees/2/addresses/3
Address 端点突然因参数而变得臃肿。
此外,如果您正在查看 Richardson Maturity Model level 3,RESTful API 应该可以通过 link 发现。例如,从顶层说 /api/version(/1),您会发现部门有一个 link。这是在像 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}"
}
(可能最终以分页方式列出所有这些的查询,或者直接转到特定部门的参数化 link,前提是您知道 ID)。
这里的优点是客户端只需要知道关系 (link) 名称,而服务器大部分时间都可以自由更改关系(和资源)url。
基于模型和安全性,我会投票给第二种解决方案。
该部门在 路径中,并且不必在有效载荷中,无论是读还是写。
如果要更改员工的部门,depID 可以包含在有效负载中或通过单独的端点(单独授予)/employees/{ID}。
旧post,但不是我满意的答案。
这取决于您的 API。如果您的数据是分层的,并且不需要访问资源而不通过其父级过滤它们,那么嵌套就可以了(也不是嵌套)。
如果您的 ID 很长 (GUID),您的层次结构很深,或者您需要访问任何资源而不被其父级过滤,那么不嵌套是一个不错的选择。
尽量有一个统一的接口,不要有多种访问同一个资源的方法
试试这个 link 可以更好地解释这一点:https://www.moesif.com/blog/technical/api-design/REST-API-Design-Best-Practices-for-Sub-and-Nested-Resources/
我的问题是关于在为 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
。我不认为这是嵌套的。
当我说嵌套资源时,我指的是像 /departments/1/employees
这样的 URL,其中一个资源总是在另一个资源的上下文中寻址。主要问题是 为了 URL 构建,通用库需要知道额外的东西 ,例如 "employees are nested under departments" 但 "branches are not nested under anything"。如果所有资源都可以 RESTfully 方式寻址,但以平面方式寻址,那么知道如何寻址它们会更简单、更准确table。
仔细想想,在数据库中,您不需要知道额外的信息就可以知道如何处理一组对象(例如 RDMS 中的 table)。您总是将员工集合称为 employees
,而不是 departments/5/employees
。
根据我的经验: Q1。由于关系模型,更易于使用,难以实现 Q2。在权限和其他潜在检查方面,嵌套更好,您可以在降级之前进行这些检查
如果您想向下钻取更多级别会怎样?
/api/addresses?departmentId=1&employeeId=2&addressId=3
对
/api/departments/1/employees/2/addresses/3
Address 端点突然因参数而变得臃肿。
此外,如果您正在查看 Richardson Maturity Model level 3,RESTful API 应该可以通过 link 发现。例如,从顶层说 /api/version(/1),您会发现部门有一个 link。这是在像 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}"
}
(可能最终以分页方式列出所有这些的查询,或者直接转到特定部门的参数化 link,前提是您知道 ID)。
这里的优点是客户端只需要知道关系 (link) 名称,而服务器大部分时间都可以自由更改关系(和资源)url。
基于模型和安全性,我会投票给第二种解决方案。
该部门在 路径中,并且不必在有效载荷中,无论是读还是写。
如果要更改员工的部门,depID 可以包含在有效负载中或通过单独的端点(单独授予)/employees/{ID}。
旧post,但不是我满意的答案。
这取决于您的 API。如果您的数据是分层的,并且不需要访问资源而不通过其父级过滤它们,那么嵌套就可以了(也不是嵌套)。
如果您的 ID 很长 (GUID),您的层次结构很深,或者您需要访问任何资源而不被其父级过滤,那么不嵌套是一个不错的选择。
尽量有一个统一的接口,不要有多种访问同一个资源的方法
试试这个 link 可以更好地解释这一点:https://www.moesif.com/blog/technical/api-design/REST-API-Design-Best-Practices-for-Sub-and-Nested-Resources/