让我们假设我想设计一个REST api来讨论歌曲,专辑和艺术家(实际上我这样做,比如我之前的1312414人).
歌曲资源始终与其所属的专辑相关联.相反,专辑资源与其包含的所有歌曲相关联.关联通过链接在资源表示中表示.
因此,表示看起来像这样:
{
song: 'xyz',
links: [
{ rel: 'album', url: '.../albums/abc' }
]
}
{
album: 'abc',
links: [
{ rel: 'song', url: '.../songs/xyz' },
{ rel: 'song', url: '...' },
{ rel: 'song', url: '...' },
{ rel: 'song', url: '...' }
]
}
Run Code Online (Sandbox Code Playgroud)
鉴于,我希望这一点成立(也许问题在于"给定"),然后如何设计我的API,以便创建专辑或歌曲资源对以前存在的歌曲或专辑没有副作用资源?
这是某种鸡/蛋问题.如果我首先创建歌曲资源(POST/songs /)然后创建专辑资源(POST /专辑/),则歌曲资源会在专辑创建过程中被修改(根据REST原则这是不好的),因为该关联两个资源之间正在服务器上更新.同样,对于我首先创建专辑的场景,第二首歌曲.
我想我可以通过避免服务器上的副作用并将管理双向关系的负担传递给客户端来避免整个问题.
另外,我不希望作为一个整体原子地创建专辑和歌曲.
我现在唯一能想到的是,通过使用表示来响应资源创建,将上述副作用包含在我的API的语义中,该表示包含由于请求而被修改的资源的链接列表.这使副作用显而易见,但仍然不安宁.
REST 中没有任何内容表明对一种资源的状态的操作不能改变另一种资源的状态。REST 与此最接近的是幂等操作的概念,它只是说重复这些操作将导致相同的状态。
Song因此,就您而言,资源能够有效地将自身添加到资源中并没有本质上的错误Album。Album资源能够说资源Song是它的一部分也没有什么本质上的错误。
现在,考虑到您的业务需求,您可能需要 a.) 更改歌曲/专辑的表示方式,或者 b.) 允许歌曲/专辑以 am/m 方式相关,而不是 1/1。原因是,根据您在系统中构建数据和选择资源(即可寻址单元)的方式,您实际上正在建模不同的数据关系,我认为这是您面临的问题的关键。
在系统中使用Songs和Albums分离资源时,强制执行更具限制性的关系(例如 1/1 而不是 m/m)需要在内容类型中进行更多工作和规范。您必须处理这样的情况:两张不同的专辑都认为它们包含一首歌曲,但 1/1 关系不允许这样做。
如果您有一个Album明确包含或拥有该对象Song的对象,那么问题就不那么大了,因为 anAlbum只能操纵它自己的歌曲,而不能操纵任何其他 的歌曲Album。然而,这改变了数据模型,因为Songs它们不再是一等公民,而是位于拥有它们的专辑下面。
这就是整个问题的关键……你必须决定谁拥有这段关系。
双方(Album和Song)拥有它并没有什么问题。这对于 am/m 关系非常有效,但对于 1/1 关系,则需要更多的管理开销(即其他东西实际上拥有该关系)。
但是,如果您想要一种没有所有开销的 1/1 关系,则必须让参与实体之一拥有该关系,这意味着只有一种路径可以更改它……通过拥有实体。