REST API 设计多余的 id

REST API Design superfluous ids

正在与某人争论 REST API 设计。

我有路线 GET /customersGET /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 是否符合良好做法?

另一方的一个论点是博客中的这个例子:

GET /cars/711/drivers/4

但据我所知,如果 4 不是唯一标识符,而是示例中的枚举(这辆车的第四位驾驶员),这仅适用于良好做法。

更多信息:

其实GET /projects暂时不用。所以我也想过添加它并使用GET /projects?customerid=<c-id>而不是GET /customers/<c-id>/projects。你怎么看?

还有问题的应用程序有一个权限层。因此,不允许访问特定客户的人不应被允许访问该客户的项目,即使他知道项目 ID。有人认为这种限制在 GET /customers/<c-id>/projects/<p-id> 路由中表达得更好。 (权限实际上取决于用户 ID 属性,该属性同样是客户和项目的 属性。)这会改变您对问题的回答吗?

我们在这里讨论两种方法。

  1. 将url划分为custId + projId *

是的。我更喜欢这种方法,因为与另一种方法相比,它更容易处理授权机制。


如果这也是 3 个不同的客户具有相同项目 ID 的情况,那么这种类型的结构也会有所帮助。

  1. 直接使用项目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 是值得的额外工作无需强制对您的客户进行不必要的更改。