这个问题涉及到REST API最佳设计以及我在选择嵌套资源和根级别集合之间遇到的问题。
为了说明概念,假设我有集合City
, Business
, 和 Employees
。一个典型的API可能构建如下。假设ABC、X7N和WWW是键,例如guids:
GET Api/City/ABC/Businesses (returns all Businesses in City ABC)
GET Api/City/ABC/Businesses/X7N (returns business X7N)
GET Api/City/ABC/Businesses/X7N/Employees (returns all employees at business X7N)
PUT Api/City/ABC/Businesses/X7N/Employees/WWW (updates employee WWW)
这看起来很干净,因为它遵循原始域结构-业务位于城市中,员工位于业务中。通过集合下的键访问各个项(例如, ../Businesses
返回所有业务,而 ../Businesses/X7N
返回单个业务)。
以下是API消费者需要能够执行的操作:
- 获取城市中的业务
(GET Api/City/ABC/Businesses)
- 获取业务中所有员工
(GET Api/City/ABC/Businesses/X7N/Employees)
- 更新单个员工信息
(PUT Api/City/ABC/Businesses/X7N/Employees/WWW)
尽管第二个和第三个调用似乎在正确的位置,但实际上使用了很多不必要的参数。
- 要获取业务中的员工,仅需要业务的键(
X7N
)。 - 要更新单个员工,仅需要员工的键(
WWW
)。
后端代码中没有要求非键信息来查找业务或更新员工。因此,以下端点似乎更好:
GET Api/City/ABC/Businesses (returns all Businesses in City ABC)
GET Api/Businesses/X7N (returns business X7N)
GET Api/Businesses/X7N/Employees (returns all employees at business X7N)
PUT Api/Employees/WWW (updates employee WWW)
如您所见,我已为企业和员工创建了一个新的根,尽管从域的角度来看它们是一个子/子子集合。
对我来说,两种解决方案都不太干净。
- 第一个示例要求提供不必要的信息,但其结构方式对消费者(通过较低层次检索集合中的个别项)似乎很“自然”。
- 第二个示例仅要求提供必要的信息,但其结构方式不太“自然”- 子集合可通过根访问。
- 独立的员工根无法在添加新员工时使用,因为我们需要知道将员工添加到哪个企业,这意味着该调用至少必须驻留在Business根下,例如
POST Api/Businesses/X7N7/Employees
,这使一切变得更加混乱。
有没有一种更简洁的第三种方法,我没有想到的?