REST API 设计多余的 id
REST API Design superfluous ids
正在与某人争论 REST API 设计。
我有路线 GET /customers
和 GET /customers/<c-id>
,其中 c-id 是客户的 ID。
现在的问题是为项目添加路由。
GET /customers/<c-id>/projects
给出一个客户的所有项目。有人建议现在添加 GET /customers/<c-id>/projects/<p-id>
以获取有关某个特定项目的信息。我对此有一种不好的预感。由于 p-id 是所有项目的唯一 ID,因此请求中根本不需要 c-id。 GET /projects/<p-id>
应该就可以了。 c-id 也是返回项目的一个属性 json(每个项目只属于一个客户)。所以这是这里的主要问题:在我看来,在请求中使用多余的 c-id 是否符合良好做法?
另一方的一个论点是博客中的这个例子:
但据我所知,如果 4 不是唯一标识符,而是示例中的枚举(这辆车的第四位驾驶员),这仅适用于良好做法。
更多信息:
其实GET /projects
暂时不用。所以我也想过添加它并使用GET /projects?customerid=<c-id>
而不是GET /customers/<c-id>/projects
。你怎么看?
还有问题的应用程序有一个权限层。因此,不允许访问特定客户的人不应被允许访问该客户的项目,即使他知道项目 ID。有人认为这种限制在 GET /customers/<c-id>/projects/<p-id>
路由中表达得更好。 (权限实际上取决于用户 ID 属性,该属性同样是客户和项目的 属性。)这会改变您对问题的回答吗?
我们在这里讨论两种方法。
- 将url划分为custId + projId *
是的。我更喜欢这种方法,因为与另一种方法相比,它更容易处理授权机制。
如果这也是 3 个不同的客户具有相同项目 ID 的情况,那么这种类型的结构也会有所帮助。
直接使用项目Id访问
在这种方法中,您必须先检索 custId,然后检查授权。
GET /customers/<c-id>/projects/<p-id>
看起来是更好的选择:
- 它清楚地表明每个项目都分配给一个客户
- 很明显,只有当用户有权访问
/customers/<c-id>
时,他才能调用/customers/<c-id>/projects/*
<p-id>
是全局唯一的这一事实是一个实现细节,不必在 REST API 中传达
So this is the main question here: is it consistent with good practice to have the in my opinion superfluous c-id in the request?
当然可以,为什么不呢?
REST 不关心 URI 的拼写。
我认为你纠结的地方; 没有规则 规定域模型中的每个实体必须有一个且只有一个 资源 与之关联。
完全可以接受拥有像
这样的资源
/customers/<c-id>/projects/<p-id>
/customers/<c-id>/projects/<local-index>
/projects/<p-id>
/9e7b964a-c87a-4184-84b1-24132aabab66
所有 映射到域模型中的相同概念,因此 return 相同的表示,或相互重定向,或其他。
It was argued that this restriction is better expressed in the GET /customers//projects/ route. (The permission is actually decided upon a user-id attribute which is a property of customer and project likewise.) Would this change your answer to the question?
否,因为身份识别和安全是正交问题。
Actually GET /projects is not used at the moment. So I also thought about adding it and using GET /projects?customerid= instead of GET /customers//projects. What do you think about that?
和以前一样
/customers/<c-id>/projects
/projects?customerid=<c-id>
/a685ee45-f366-462b-a47a-dff61f98dd1e
...都是非常合理的选择。
您可能要考虑的一件事是 RFC 3986, which specifies the rules for computing a new identifier given a base and a relative reference。点段可以很方便地 shorthand 将客户端定向到另一个引用,而无需担心当前范围内的基本标识符。
如果您的目标是设计经得起时间考验的 RESTful API,那么您的客户不应该真正关心您的 URL 的外观。
(即拥抱 HATEOS)
事实上,您应该坚持要求您的客户不要尝试基于某种形式的 URL 模板构建 URL。
如果客户需要获取客户的项目列表,您的超文本(即返回给客户的资源表示)应包含 URL + 操作说明。
这就是 HTML 处理它的方式:您会得到一个表单 URL 和各种 HTML 标签,这些标签描述了如何向 URL 添加参数以查找特定的资源。
这就是为什么您可以拥有一个通用的客户端应用程序(浏览器),例如,一家银行。浏览器不关心账户是什么,它只知道如何检索资源。
如果您无法控制您的客户(向您的服务发出请求的软件)是谁,并且您希望在未来许多年内发展您的 API,那么实现完整的 REST 是值得的额外工作无需强制对您的客户进行不必要的更改。
正在与某人争论 REST API 设计。
我有路线 GET /customers
和 GET /customers/<c-id>
,其中 c-id 是客户的 ID。
现在的问题是为项目添加路由。
GET /customers/<c-id>/projects
给出一个客户的所有项目。有人建议现在添加 GET /customers/<c-id>/projects/<p-id>
以获取有关某个特定项目的信息。我对此有一种不好的预感。由于 p-id 是所有项目的唯一 ID,因此请求中根本不需要 c-id。 GET /projects/<p-id>
应该就可以了。 c-id 也是返回项目的一个属性 json(每个项目只属于一个客户)。所以这是这里的主要问题:在我看来,在请求中使用多余的 c-id 是否符合良好做法?
另一方的一个论点是博客中的这个例子:
但据我所知,如果 4 不是唯一标识符,而是示例中的枚举(这辆车的第四位驾驶员),这仅适用于良好做法。
更多信息:
其实GET /projects
暂时不用。所以我也想过添加它并使用GET /projects?customerid=<c-id>
而不是GET /customers/<c-id>/projects
。你怎么看?
还有问题的应用程序有一个权限层。因此,不允许访问特定客户的人不应被允许访问该客户的项目,即使他知道项目 ID。有人认为这种限制在 GET /customers/<c-id>/projects/<p-id>
路由中表达得更好。 (权限实际上取决于用户 ID 属性,该属性同样是客户和项目的 属性。)这会改变您对问题的回答吗?
我们在这里讨论两种方法。
- 将url划分为custId + projId *
是的。我更喜欢这种方法,因为与另一种方法相比,它更容易处理授权机制。
如果这也是 3 个不同的客户具有相同项目 ID 的情况,那么这种类型的结构也会有所帮助。
直接使用项目Id访问
在这种方法中,您必须先检索 custId,然后检查授权。
GET /customers/<c-id>/projects/<p-id>
看起来是更好的选择:
- 它清楚地表明每个项目都分配给一个客户
- 很明显,只有当用户有权访问
/customers/<c-id>
时,他才能调用/customers/<c-id>/projects/*
<p-id>
是全局唯一的这一事实是一个实现细节,不必在 REST API 中传达
So this is the main question here: is it consistent with good practice to have the in my opinion superfluous c-id in the request?
当然可以,为什么不呢?
REST 不关心 URI 的拼写。
我认为你纠结的地方; 没有规则 规定域模型中的每个实体必须有一个且只有一个 资源 与之关联。
完全可以接受拥有像
这样的资源/customers/<c-id>/projects/<p-id>
/customers/<c-id>/projects/<local-index>
/projects/<p-id>
/9e7b964a-c87a-4184-84b1-24132aabab66
所有 映射到域模型中的相同概念,因此 return 相同的表示,或相互重定向,或其他。
It was argued that this restriction is better expressed in the GET /customers//projects/ route. (The permission is actually decided upon a user-id attribute which is a property of customer and project likewise.) Would this change your answer to the question?
否,因为身份识别和安全是正交问题。
Actually GET /projects is not used at the moment. So I also thought about adding it and using GET /projects?customerid= instead of GET /customers//projects. What do you think about that?
和以前一样
/customers/<c-id>/projects
/projects?customerid=<c-id>
/a685ee45-f366-462b-a47a-dff61f98dd1e
...都是非常合理的选择。
您可能要考虑的一件事是 RFC 3986, which specifies the rules for computing a new identifier given a base and a relative reference。点段可以很方便地 shorthand 将客户端定向到另一个引用,而无需担心当前范围内的基本标识符。
如果您的目标是设计经得起时间考验的 RESTful API,那么您的客户不应该真正关心您的 URL 的外观。 (即拥抱 HATEOS) 事实上,您应该坚持要求您的客户不要尝试基于某种形式的 URL 模板构建 URL。
如果客户需要获取客户的项目列表,您的超文本(即返回给客户的资源表示)应包含 URL + 操作说明。
这就是 HTML 处理它的方式:您会得到一个表单 URL 和各种 HTML 标签,这些标签描述了如何向 URL 添加参数以查找特定的资源。 这就是为什么您可以拥有一个通用的客户端应用程序(浏览器),例如,一家银行。浏览器不关心账户是什么,它只知道如何检索资源。
如果您无法控制您的客户(向您的服务发出请求的软件)是谁,并且您希望在未来许多年内发展您的 API,那么实现完整的 REST 是值得的额外工作无需强制对您的客户进行不必要的更改。