Rest API 设计:管理对子实体的访问

Rest API design: Managing access to sub-entities

注意:我意识到这接近于基于意见的离题,但我希望有一些公认的最佳实践来处理这个我只是不知道关于.

我的问题如下:我需要为一个程序设计一个 Rest API,用户可以在其中创建自己的项目,并且每个项目都包含只有具有访问权限的用户才能看到的文件。我对如何设计“列出项目的所有文件”查询感到困惑。

标准休息 API 练习会建议两个终点,例如:

`GET /projects`     # List all projects
`POST /projects`    # Create new project
`GET /projects/id`  # Get specific project
etc.

项目文件同理

但是,永远不应有理由列出所有 个文件——仅列出单个项目的文件。更复杂的是,访问管理需要成为一件事,用户永远不应该看到他们无权访问的项目中的文件。

我可以看到多种处理方法:

  1. 所以显而易见的方法是实现 GET 函数,可选地使用过滤器。然而,这并不是最优的,因为如果用户没有设置过滤器,它将不得不遍历所有项目,检查每个项目用户是否有访问权限,然后列出用户有权访问的所有文件:

    GET /files?project=test1

  2. 我还可以让文件命令成为项目命令的子命令——例如

    GET /projects/#id/files

    但是,我觉得这不太 restful,因为它不直接公开实体?

有什么共同点应该经常执行的吗?可以“强制”用户在第一个中设置一个参数吗?或者是否有第三种选择可以解决我正在寻找的问题?对有关如何设计它的任何文献建议也感到高兴。

进一步查看后,我遇到了来自 Microsoft 的 this document。一些引用:

Also consider the relationships between different types of resources and how you might expose these associations. For example, the /customers/5/orders might represent all of the orders for customer 5. You could also go in the other direction, and represent the association from an order back to a customer with a URI such as /orders/99/customer. However, extending this model too far can become cumbersome to implement. A better solution is to provide navigable links to associated resources in the body of the HTTP response message. This mechanism is described in more detail in the section Use HATEOAS to enable navigation to related resources.

In more complex systems, it can be tempting to provide URIs that enable a client to navigate through several levels of relationships, such as /customers/1/orders/99/products. However, this level of complexity can be difficult to maintain and is inflexible if the relationships between resources change in the future. Instead, try to keep URIs relatively simple. Once an application has a reference to a resource, it should be possible to use this reference to find items related to that resource. The preceding query can be replaced with the URI /customers/1/orders to find all the orders for customer 1, and then /orders/99/products to find the products in this order.

这让我觉得使用解决方案 2 对我来说可能是最好的情况,因为每个文件将只与一个项目相关联,并且应该在删除项目时删除。文件不能独立存在于项目之外。

Standard Rest API practice would suggest two endpoints

不,不会。 REST 实践建议找出资源模型中的资源。

考虑“文档”:我应该能够检索 (GET) 描述项目中所有文件的文档。伟大的!只有当请求授权匹配某些访问控制列表时,才应该可以访问该文档。也不错

也许每个用户还应该有一个文档,这样他们就可以看到他们有权访问的所有项目的列表,其中该文档包含指向“项目中的所有文件”文档的链接。当然,该文档也应该受到访问控制。

请注意,此处的“文档”可能是文本、媒体文件、脚本或 CSS,或者几乎任何可以通过网络传输的信息。我们可以忽略细节,因为“统一接口”意味着我们以相同的方式管理它们。

换句话说,我们只是在设计一个充满相互链接的文档并具有访问控制的“网站”。

每个文档都需要一个唯一标识符。该标识符可以是我们想要的任何东西:/5393d5b0-0517-4c13-a821-c6578cb97668fine。因为它可以是我们想要的任何东西,所以我们有额外的自由度。

例如,我们可以设计我们的标识符,使得标识符以 /users/12345 开头的文档只能由具有与用户 12345 匹配的授权 headers 的请求访问,并且标识符以 /users/12345 开头的所有文档with /projects/12345 只能由具有授权 headers 的请求访问,该请求与有权访问该特定项目的任何用户相匹配,依此类推。

换句话说,选择使您的实施更容易的资源标识符拼写是完全可以接受的。

(注意:在理想情况下,您将拥有与实现无关的“酷”标识符,因此即使您更改了服务器的底层实现细节,它们仍然有效。)

I have the feeling this isn't too restful, since it doesn't expose entities directly?

没关系。资源模型和实体模型是不同的东西;我们不应该期望它们总是一对一匹配。