据我所知,每个资源都应该有 only one canonical 路径 . 因此,在下面的示例中,良好的URL模式是什么?
以公司的休息代表为例 . 在这个假设的例子中,每个公司 owns 0或更多部门和每个部门 owns 0或更多员工 .
没有关联公司的部门 can't exist .
没有关联部门的员工 can't exist .
现在我会找到资源模式的自然表示 .
-
/companies
公司集合 - 接受新公司的接受 . 获取整个系列 . -
/companies/{companyId}
一家公司 . 接受GET,PUT和DELETE -
/companies/{companyId}/departments
接受新项目的POST . (在公司内部创建一个部门 . ) -
/companies/{companyId}/departments/{departmentId}/
-
/companies/{companyId}/departments/{departmentId}/employees
-
/companies/{companyId}/departments/{departmentId}/employees/{empId}
考虑到约束,在每个部分中,我觉得如果有点深度嵌套,这是有道理的 .
但是,如果我想列出( GET
)所有公司的所有员工,我的困难就来了 .
该资源模式最贴切地映射到 /employees
(所有员工的集合)
这是否意味着我应该 /employees/{empId}
也因为如果是这样,那么有两个URI可以获得相同的资源?
或者整个架构可能会被展平,但这意味着员工是嵌套的顶级对象 .
在基本级别 /employees/?company={companyId}&department={deptId}
返回与最深层嵌套模式完全相同的员工视图 .
对于其他资源资源是 owned 但应该可以单独查询的URL模式的最佳做法是什么?
UPDATE: 请参阅下面的答案,看看我做了什么 .
6 回答
你所做的是正确的 . 通常,同一资源可能有许多URI - 没有规则表明您不应该这样做 .
通常,您可能需要直接访问项目或作为其他内容的子集 - 因此您的结构对我来说很有意义 .
仅仅因为员工可以在部门下访问:
company/{companyid}/department/{departmentid}/employees
并不意味着他们也无法在公司下访问:
company/{companyid}/employees
哪个会让该公司的员工回归 . 这取决于您的消费客户需要什么 - 这就是您应该设计的内容 .
但我希望所有URL处理程序使用相同的支持代码来满足请求,这样您就不会复制代码 .
我尝试了两种设计策略 - 嵌套和非嵌套 endpoints . 我发现:
如果嵌套资源具有主键且您没有其主键,则嵌套结构要求您获取它,即使系统实际上并不需要它 .
嵌套 endpoints 通常需要冗余 endpoints . 换句话说,您通常需要额外的/员工 endpoints ,以便获得跨部门的员工列表 . 如果您有/员工,/公司/部门/员工到底会给您带来什么?
嵌套 endpoints 不会很好地发展 . 例如 . 您现在可能不需要搜索员工,但是您可能以后也可以,如果您有嵌套结构,则别无选择,只能添加另一个 endpoints . 使用非嵌套设计,您只需添加更多参数,这更简单 .
有时资源可能有多种类型的父母 . 导致多个 endpoints 都返回相同的资源 .
冗余 endpoints 使得文档更难写,也使得api更难学习 .
简而言之,非嵌套设计似乎允许更灵活和更简单的 endpoints 模式 .
我把我从问题所做的事情转移到了更多人可能会看到它的答案 .
我所做的是在嵌套 endpoints 上创建创建 endpoints ,修改或查询项目的规范 endpoints 是 not at the nested resource .
所以在这个例子中(只列出更改资源的 endpoints )
POST
/companies/
创建新公司返回创建公司的链接 .放置部门时
POST
/companies/{companyId}/departments
创建新部门会返回指向/departments/{departmentId}
的链接PUT
/departments/{departmentId}
修改了一个部门POST
/departments/{deparmentId}/employees
创建新员工返回指向/employees/{employeeId}
的链接因此,每个集合都有根级资源 . 但是 create 在 owning 对象中 .
我不同意这种道路
如果你想获得部门,我认为最好使用/ departments资源
我想你有一个
companies
表和一个departments
表然后用你用你编程语言映射它们的类 . 我还假设部门可以附加到除公司之外的其他实体,因此/部门资源很简单,因为您可以重用,所以需要尽可能多的 endpoints例如,对于任何类型的搜索
如果你想创建一个部门,那么
应使用资源,请求正文应包含公司ID(如果部门只能链接到一家公司) .
您的网址外观与REST无关 . 什么都可以 . 它实际上是一个“实现细节” . 就像你如何命名变量一样 . 它们必须具有独特性和耐用性 .
不要在此浪费太多时间,只需做出选择并坚持下去/保持一致 . 例如,如果您使用层次结构,那么您可以为所有资源执行此操作 . 如果您使用查询参数...等,就像代码中的命名约定一样 .
为什么这样 ?据我所知,“RESTful”API是可浏览的(你知道......“超媒体作为应用程序状态的引擎”),因此API客户端不关心你的URL是什么样的,只要它们是有效(没有搜索引擎优化,没有人需要阅读那些“友好的网址”,除了可能用于调试......)
How nice/understandable a URL is in a REST API is only interesting to you as the API developer, not the API client, as would the name of a variable in your code be.
最重要的是,您的API客户端知道如何解释您的媒体类型 . 例如,它知道:
您的媒体类型有一个链接属性,列出可用/相关链接 .
每个链接都由关系标识(就像浏览器知道链接[rel = "stylesheet"]表示其样式表或rel = favico是指向图标的链接...)
并且它知道这些关系意味着什么("companies"表示公司列表,"search"表示在资源列表上进行搜索的模板化URL,"departments"表示当前资源的部门)
下面是一个示例HTTP交换(正文是yaml,因为它更容易编写):
Request
Response: 主要资源的链接列表(公司,人员,等等......)
Request: 链接到公司(使用以前的回复的body.links.companies)
Response: 公司的部分清单(在项目下),资源包含相关链接,如获取下一对公司的链接(body.links.next)另一个(模板化)搜索链接(body.links.search)
因此,当您看到链接/关系方式如何构建URL的路径部分时,您的API客户端没有任何 Value . 如果您正在将URL的结构作为文档传达给客户端,那么您不会使用REST(或者至少不是“Richardson's maturity model”的3级)
我已经阅读了上述所有答案,但似乎没有共同的策略 . 我发现了一篇关于best practices in Design API from Microsoft Documents的好文章 . 我想你应该参考 .
.