假设我有一个拥有多个帐户的客户。实际上任何与另一个复杂对象具有“1对多”关系的数据对象都可以。
一个例子可能是:
/customers/1
我的问题是,何时将帐户作为客户的子资源公开,而不是作为单独的资源?或两者兼而有之?
例如,我的第一个直觉就是:POST
返回上面的对象。如果您想修改其中一个帐户,则必须/accounts/2
到/customers/1/accounts
。
另一种方法(我已经在一些API中看到)是暴露另一条路由POST
,它将返回上面的数组,然后设置PATCH
/ {{1}}在那里路由以允许API用户改变帐户数组。
我对这种方法的问题是,如果帐户数组实际上是“按引用包含”,那么REST路由是否正在修改帐户或者它是否只是修改并不是很清楚客户与帐户之间的联系。
这里有最好的做法吗?
答案 0 :(得分:4)
这是一个很好的问题,需要讨论(没有“正确”的答案)。以下是您可能需要考虑的一些要点:
将子帐户资源嵌入客户资源将导致更多数据始终与/ customers / {id}请求一起发回。
如果子帐户资源需要非嵌入式,则需要客户端在需要基本客户信息和帐户信息时发送多个HTTP请求。
您需要准确确定安全范例如何与嵌入式资源配合使用。 (即是否可以获取客户的信息但不允许查看客户账户?)
在您的域中拥有一个没有客户的帐户是否有意义?帐户可以转让所有权?如果没有,则/ customers / {id} / accounts / {acct_id}更有意义。
在REST的定义中暗示,在URI上发布HTTP方法正在修改由URI标识的资源,因此默认情况下,您总是修改帐户而不是客户和帐户之间的链接。
如果您需要修改帐户关联的功能,您可以创建一个资源,例如“帐户链接请求”(POST / accounts / {id} / linkreqeust或类似的东西)。此请求本身可以具有一个状态,您可以在其中使用后端功能来评估请求,然后确定是否应该将客户链接或分离到客户,然后执行附加/分离过程。 / p>
总之,REST中没有任何内容阻止您引用具有不同链接的相同资源(/ accounts / {id}; / customers / {id} / accounts / {acct_id})。我的偏好是,如果对子资源没有安全隐患,那么将其与端点一起使用以自己访问子资源。如果帐户可能与多个用户绑定(或没有客户),我还会公开/ accounts / {id}端点。
ex. /customers/1:
{
"id": "1",
"name": "John Doe",
"accounts": {
"collection": [
{
"id": "1",
"type": "savings",
"balance": "$400",
"links": {
"self": "/customers/1/accounts/1"
}
},
{
"id": "2",
"type": "checking",
"balance": "$600",
"links": {
"self": "/customers/1/accounts/2",
"detach" : "/customers/1/accounts/2/linkrequest?action=detach"
}
}
],
"links": {
"self": "/customers/1/accounts",
"attach": "customers/1/accounts/linkrequest?action=attach"
}
},
"links": {
"self": "/customers/1"
}
}
答案 1 :(得分:1)
正如您已经怀疑的那样,所有这些都归结为数据库中的数据表示模型。它是一个拥有的关系(实际实体列表),无主关系(你称之为“引用包含”),甚至是反向链接引用的隐式1:N关系(帐户上的客户反向链接字段)。
为了通过GET检索数据,可以根据表示模型使用以下内容:
/customers/1/accounts
/accounts?customer eq 1