与某人争论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,如果4不是唯一标识符,而是示例中的枚举(此车的第四个驱动程序)。
更多的信息:
实际上目前没有使用GET /projects
。所以我也考虑添加它并使用GET /projects?customerid=<c-id>
而不是GET /customers/<c-id>/projects
。你觉得怎么样?
此外,该应用程序还有一个权限层。因此,即使他知道项目ID,也不应允许不允许访问特定客户的人访问该客户的项目。有人认为,这种限制在GET /customers/<c-id>/projects/<p-id>
路线中得到了更好的表达。 (该权限实际上取决于user-id属性,该属性同样是客户和项目的属性。)这会改变您对问题的答案吗?
所以这是这里的主要问题:在我看来,在请求中使用多余的c-id是否符合良好做法?
当然,为什么不呢?
REST不关心您用于URI的拼写。
在哪里,我认为你纠缠不清;没有规则说您的域模型中的每个实体都必须只有一个与之关联的资源。
拥有像这样的资源是完全可以接受的
/customers/<c-id>/projects/<p-id>
/customers/<c-id>/projects/<local-index>
/projects/<p-id>
/9e7b964a-c87a-4184-84b1-24132aabab66
所有这些都映射到域模型中的相同概念,因此返回相同的表示形式,或相互重定向,或者其他任何方式。
有人认为,这种限制在GET /客户//项目/路线中得到了更好的表达。 (该权限实际上取决于user-id属性,该属性同样是客户和项目的属性。)这会改变您对问题的答案吗?
不,因为识别和安全是正交问题。
实际上目前没有使用GET /项目。所以我也想过添加它并使用GET / projects?customerid =而不是GET / customers //项目。你觉得怎么样?
和之前一样
/customers/<c-id>/projects
/projects?customerid=<c-id>
/a685ee45-f366-462b-a47a-dff61f98dd1e
...都是完全合理的选择。
你可能想要考虑的一件事是RFC 3986,它规定了computing a new identifier given a base and a relative reference的规则。点段可以是方便的简写,用于将客户端引导到另一个引用,而无需担心当前哪个基本标识符在范围内。
我们在这里讨论两种方法。
是。我会更喜欢这种方法,与其他方法相比,它更容易处理授权机制。
如果这也是3个不同客户具有相同项目ID的情况,那么这种类型的结构也将是有帮助的。
GET /customers/<c-id>/projects/<p-id>
看起来是一个更好的选择:
/customers/<c-id>
时,他才能调用/customers/<c-id>/projects/*
<p-id>
是全局唯一的这一事实是一个实现细节,不必在REST API中进行通信如果您的目标是设计经得起时间考验的RESTful API,那么您的客户应该不关心您的网址是什么样的。 (即拥抱HATEOS)事实上,您应该坚持要求您的客户不要尝试基于某种形式的URL模板构建URL。
如果客户需要获取客户的项目列表,则您的超文本(即返回给客户端的资源表示)应包含URL +如何执行此操作的说明。
这就是HTML处理它的方式:您将获得一个表单URL和各种HTML标记,这些标记描述了如何向URL添加参数以查找特定资源。这就是为什么你可以有一个通用的客户端应用程序(浏览器) - 例如 - 银行。浏览器不关心帐户是什么,它只知道如何检索资源。
如果您无法控制您的客户(向您的服务提出请求的软件)是谁,并且您希望在未来多年内不需要对客户进行不必要的更改来发展您的API,那么完整的REST是值得的额外工作。