带关联的RESTful API最佳实践



我们正在实现一个RESTful API,我们有POST请求看起来像这样的/v1/systems/{systemId}/subsystems和主体看起来像这样{"id": 0, "systemId": 0, "name": "string"}。这是变量的重复吗?这样做是很好的练习吗?

URI作为一个整体是资源的标识符,而不仅仅是最后一部分。URI本身是否遵循某种结构设计也取决于您的设计决策。就其本身而言,像.../systems/{systemId}/subsystems这样的URI不一定声明它是systems集合的一部分,其父资源由各自的systemId标识。这只会"进化"。如果客户端自然地探索的uri总体上跨越了构建此关系的树。不过,这种关系通常用链接关系表示,比如up引用父资源,item引用集合中的特定项,subsection引用集合资源的子部分,等等。查看Iana的链接关系注册表是否有适合您需要的可用链接关系。如果所有可用的链接关系都不能满足您的需求,您可以向Iana注册新的链接关系,或者使用Web链接关系扩展,您可以在自己的名称空间中定义私有关系。

关于在主体中添加systemId,当您使用URI结构时,systemId已经在路径中使用以识别父资源,那么该信息显然是冗余的。但是是否要将其包含在有效载荷中是您的设计选择。包括它或不包括它都没有错。

不幸的是,关于subsystems资源的信息相当有限。给定的当前有效负载可能被简化为名称本身,因为URI中给出了systemId,而子系统资源的id可能是自动生成的,而不是由客户机定义的。因此,有效负载将减少为单个名称。在这里,您还可以完全避免创建子资源,并通过将其设计为名称数组来在system条目本身中对子系统的名称进行建模。这里,您可以简单地为系统资源提供一个更新方法(通过Patch)来将名称添加到该数组中,而不是创建子资源。但是,这是你的设计。在这里,只要适合你就行。

作为是否在有效负载中包含此类信息的经验法则,您可以以Web为例。例如,如果ID应该是呈现给最终用户的表示的一部分,则将其放入。如果不是,就把它删掉。设想一个你想要在页面上呈现的产品。如果你想给客户一种独特的方式来解决特定产品的回收或问题,那么如果有相应的产品id,有时可能会有所帮助。但是,由于资源标识符不应该更改,因此如果可能的话,将UUID公开为内部产品标识符并携带客户应该在其他字段中使用的产品标识符可能会更有利。我们的一个客户曾经进行过一次合并,在那次合并中,他们基本上是将两家公司的产品合并在一起,在他们的数据库中使用不同的标识符。因此,他们不得不修改大量资源uri,即使产品(以其实际形式)根本没有改变。因此,不幸的是,由于没有重定向,某些客户突然无法访问以前收藏的产品描述等。这当然是一种极端和罕见的情况,尽管它可能会发生,如果您使用的设计支持这种更改,那么对整个系统的影响就会明显减少。

所以,长话短说,这取决于你的设计,systemId是否是冗余信息,或者你是否想将该信息添加到有效负载中,甚至完全避免子资源,而是在父系统本身的列表中携带该名称。这里没有正确或错误的答案。

通常情况下,不会通过POST将资源创建到指向单个资源的URL。您的URL看起来更正确的GET, PUT或DELETE。

在不知道你的确切需求的情况下,可以这样做:

POST body {"systemId": 0, "name": "string"} to /v1/systems or /v1/subsystems

响应可以包含已创建的子系统以及新的id。

最新更新