问题描述
据我所知,每个资源都应该有只有一个规范路径.所以在以下示例中,良好的URL模式是什么?
举个例子是公司的休息表示.在这个假设的例子中,每个公司拥有 0或更多部门,每个部门拥有 0或更多员工.
部门不能存在没有相关公司.
员工不能存在没有相关部门.
现在我会发现资源模式的自然表示.
- /companies 公司的集合 - 接受新公司.得到整个系列.
- /companies/{companyId}个人公司.接受,放和删除
- /companies/{companyId}/departments接受新项目的帖子. (在公司内部创建一个部门.)
- /companies/{companyId}/departments/{departmentId}/
- /companies/{companyId}/departments/{departmentId}/employees
- /companies/{companyId}/departments/{departmentId}/employees/{empId}
给出了约束,在每个部分中,如果有点嵌套,我觉得这是有意义的.
但是,如果我想列出(GET)所有员工,我的困难都是在所有公司中列出(GET).该资源模式将最接近映射到/employees(所有员工的集合)
这是否意味着我也应该有/employees/{empId},因为如果所以,那么有两个URI来获得相同的资源?
或可能整个架构应该扁平化,但这意味着员工是嵌套的顶级对象.
在基本级别/employees/?company={companyId}&department={deptId}返回员工的完全相同的视图,作为最深刻的嵌套模式.
资源拥有的URL模式的最佳实践是什么,但应该单独查询?
推荐答案
您所做的是正确的.一般来说,相同资源可能有许多URI - 没有规则说你不应该这样做.
一般而言,您可能需要直接访问项目或作为其他东西的子集 - 所以您的结构对我有意义.
只是因为员工可以在部门访问:
company/{companyid}/department/{departmentid}/employees
并不意味着他们也无法在公司下访问:
company/{companyid}/employees
将返回该公司的员工.这取决于您的消费客户端所需的内容 - 这就是您应该为设计的设计.
但我希望所有URL处理程序都使用相同的备份代码来满足请求,以便您不复制代码.
其他推荐答案
我已经尝试了设计策略 - 嵌套和非嵌套端点.我发现了:
-
如果嵌套资源具有主键并且您没有父键,则嵌套结构要求您获得它,即使系统实际上并不需要它.
-
嵌套端点通常需要冗余端点.换句话说,您将更频繁地需要额外/员工终点,因此您可以在各部门获取员工列表.如果您有/员工,究竟是什么/公司/部门/员工购买你?
-
嵌套端点不会像很好地发展.例如.您现在可能不需要搜索员工,但稍后,如果您有嵌套结构,则别无选择,只能添加另一个端点.使用非嵌套设计,您只需添加更多参数,这更简单.
-
有时资源可以有多种类型的父母.导致多个端点返回相同的资源.
-
冗余端点使文档更难编写,并且也使API更难学习.
简而言之,非嵌套设计似乎允许更灵活,更简单的端点模式.
其他推荐答案
我已经移动了我从问题所做的事情到答案,越来越容易看到它.
我所做的是在嵌套端点上拥有创建端点,用于修改或查询项目的规范端点不在嵌套资源.
所以在这个例子中(只是列出改变资源的端点)
- POST /companies/创建新公司返回创建公司的链接.
- POST /companies/{companyId}/departments当部门被配置创建新部门返回/departments/{departmentId} 的链接
- PUT /departments/{departmentId}修改部门
- POST /departments/{deparmentId}/employees创建新员工返回/employees/{employeeId} 的链接
所以每个集合都有根级资源.但是 create 是拥有对象.
问题描述
As far as I can tell each individual resource should have only one canonical path. So in the following example what would good URL patterns be?
Take for an example a rest representation of Companies. In this hypothetical example, each company owns 0 or more departments and each department owns 0 or more employees.
A department can't exist without an associated company.
An employee can't exist without an associated department.
Now I'd find the natural representation of the resource patterns to be.
- /companies A collection of companies - Accepts put for a new company. Get for the entire collection.
- /companies/{companyId} An individual company. Accepts GET, PUT and DELETE
- /companies/{companyId}/departments Accepts POST for a new item. (Creates a department within the company.)
- /companies/{companyId}/departments/{departmentId}/
- /companies/{companyId}/departments/{departmentId}/employees
- /companies/{companyId}/departments/{departmentId}/employees/{empId}
Given the constraints, in each of the sections, I feel that this makes sense if a bit deeply nested.
However, my difficulty comes if I want to list (GET) all employees across all companies.
The resource pattern for that would most closely map to /employees (The collection of all employees)
Does that mean that I should have /employees/{empId} also because if so then there are two URI's to get the same resource?
Or maybe the entire schema should be flattened but that would mean that employees are a nested top-level object.
At a basic level /employees/?company={companyId}&department={deptId} returns the exact same view of employees as the most deeply nested pattern.
What's the best practice for URL patterns where resources are owned by other resources but should be query-able separately?
推荐答案
What you have done is correct. In general there can be many URIs to the same resource - there are no rules that say you shouldn't do that.
And generally, you may need to access items directly or as a subset of something else - so your structure makes sense to me.
Just because employees are accessible under department:
company/{companyid}/department/{departmentid}/employees
Doesn't mean they can't be accessible under company too:
company/{companyid}/employees
Which would return employees for that company. It depends on what is needed by your consuming client - that is what you should be designing for.
But I would hope that all URLs handlers use the same backing code to satisfy the requests so that you aren't duplicating code.
其他推荐答案
I've tried both design strategies - nested and non-nested endpoints. I've found that:
if the nested resource has a primary key and you don't have its parent primary key, the nested structure requires you to get it, even though the system doesn't actually require it.
nested endpoints typically require redundant endpoints. In other words, you will more often than not, need the additional /employees endpoint so you can get a list of employees across departments. If you have /employees, what exactly does /companies/departments/employees buy you?
nesting endpoints don't evolve as nicely. E.g. you might not need to search for employees now but you might later and if you have a nested structure, you have no choice but to add another endpoint. With a non-nested design, you just add more parameters, which is simpler.
sometimes a resource could have multiple types of parents. Resulting in multiple endpoints all returning the same resource.
redundant endpoints makes the docs harder to write and also makes the api harder to learn.
In short, the non-nested design seems to allow a more flexible and simpler endpoint schema.
其他推荐答案
I've moved what I've done from the question to an answer where more people are likely to see it.
What I've done is to have the creation endpoints at the nested endpoint, The canonical endpoint for modifying or querying an item is not at the nested resource.
So in this example (just listing the endpoints that change a resource)
- POST /companies/ creates a new company returns a link to the created company.
- POST /companies/{companyId}/departments when a department is put creates the new department returns a link to /departments/{departmentId}
- PUT /departments/{departmentId} modifies a department
- POST /departments/{deparmentId}/employees creates a new employee returns a link to /employees/{employeeId}
So there are root level resources for each of the collections. However the create is in the owning object.