如何在RESTful API中创建/更新多对多关系

时间:2015-06-26 03:46:16

标签: api rest restful-architecture

这是您在我的API中向玩家添加玩家的方式:

PUT /teams/1/players/1/

我现在想要将玩家改为另一支球队。

我该怎么做?

3 个答案:

答案 0 :(得分:3)

我可以尊重地建议不这样做吗?相反,请将/players/teams作为顶级资源。使用播放器上的属性控制玩家所在的团队。然后,您可以通过PUT使用新的团队价值来更新玩家的团队。

或者,创建一个包含所有玩家团队映射的新顶级资源,例如'/ team-membership'。然后,您可以查询GET /team-memberships?teamId=7GET /team-memberships?playerId=2。您可以发布和删除此资源,以添加和删除团队中的玩家。

从概念上讲,玩家不是团队的子资源。玩家是与团队相关联的独立资源。我认为上述任何一种方法都会为您提供更大的灵活性,更易于理解和使用。

答案 1 :(得分:2)

通常通过HTTP PUTHTTP PATCH来更改资源(如果只执行部分更新,则更改后者)。但是,使用像PUT /teams/1/players/1?moveToTeam=2之类的构造有一些语义问题,即用请求正文中找到的有效负载替换当前表示。可选的查询参数是您在服务器端调用以将玩家从第1组移动到第2组的方法。但是,HTTP PUT是幂等操作,这基本上意味着如果您执行两次相同的语句,它将产生相同的影响。但是,当您从第1组中删除播放器并将当前用户的数据复制到新位置时,调用相同的方法会违反HTTP PUT的幂等性质,因为连续调用将失败为{{1}资源可用或者没有播放器的内容可用,因此移动的播放器的内容也将设置为空体。因此,我不建议使用/teams/1/players/1

可能HTTP PUT是您将玩家从一个团队移动到另一个团队时最接近的单一HTTP操作。此请求成功删除了团队1中的播放器,该播放器在调用后不应该可用,因此进一步调用不会更改资源(幂等)。该操作应返回DELETE /teams/1/players/1?moveToTeam=2,包括播放器实体的新状态,该链接应该指向其新位置。根据规范,200 OK还允许移动资源。但是,规范声明在执行操作后不应该访问此资源。

  

DELETE方法请求源服务器删除Request-URI标识的资源。可以通过源服务器上的人为干预(或其他方式)覆盖此方法。即使从源服务器返回的状态代码指示操作已成功完成,也无法保证客户端已执行该操作。但是,服务器不应该指示成功,除非在给出响应时,它打算删除资源或将其移动到无法访问的位置

     

如果响应包括描述状态的实体,则成功响应应为200(OK),如果操作尚未执行,则应为202(已接受);如果已执行操作但响应为204(无内容)不包括实体。 (Source

因此,如果您尝试完全RESTful IMO,则此操作有点冒险。

因此,我建议将操作拆分为原子单位:

  • 检索要临时移动和存储的用户的当前数据(HTTP DELETE
  • 从第1组(GET /teams/1/players/1
  • 中删除该播放器
  • 将玩家添加到您希望玩家所属的团队中。在请求中使用临时存储的数据作为有效负载(DELETE /teams/1/players/1
  • 为仍然引用POST /teams/2/players的用户创建重定向(301 Moved Permanently),以便他们自动转发到GET /teams/1/players/1,其中GET /teams/2/players/n是新的ID播放器。

每个操作都遵循HTTP规范中定义的规则,因此将请求分成原子部分应该很好。

<强>更新

虽然我同意@EricStein将玩家与他们自己的资源分开,因为这简化了玩家从team1到team2的大幅度移动,我还看了n方法,看起来更多适合于PATCH或将移动分成多个原子请求。

DELETE通常是confused with a partial update,其中只将资源属性的新值发送到服务器,而不是。 PATCH的结果可能相等,但PATCH发送服务器必须执行的必要步骤,以便将资源从一个状态转换为新状态。规范明确指出:

  

PATCH方法请求中描述的一组更改      请求实体应用于请求所标识的资源 -      URI。这组更改以称为&#34;补丁的格式表示      文件&#34;由媒体类型识别。如果Request-URI没有      指向现有资源,服务器可以创建新资源,      取决于补丁文档类型(是否可以在逻辑上修改      空资源)和权限等。

     

PUT和PATCH请求之间的区别反映在      服务器处理封闭实体以修改资源的方式      由Request-URI标识。在PUT请求中,包含的实体      被认为是存储在该资源上的资源的修改版本      原始服务器,客户端请求存储的版本      被替换。 但是,对于PATCH,随附的实体包含一个集合      描述资源当前如何驻留在      应修改原始服务器以生成新版本。 PATCH      方法影响Request-URI标识的资源,它      也可能对其他资源产生副作用;即新资源      可以通过应用a来创建或修改现有的      补丁。Source

特别是最后引用的行说明它可能有副作用并可能创建新资源。因此,如果您因任何原因无法更改模型,PATCH可能是将玩家从一个团队转移到另一个团队的最佳方式。此方法允许您发送服务器必须执行的必要步骤,以便为移动的播放器创建新资源,删除旧表示并在单个请求中建立到新资源的永久转发。但是,这种操作既不安全也不是幂等的!

答案 2 :(得分:0)

如何做类似POST /teams/1/players/5/transfers的事情。这将具有创建“ Team Player Transfer”的效果。网址中提供了id中的TeamPlayer,正文可以是{ new_team_id: 2 }之类。然后服务器可以按自己喜欢的方式执行“传输”。

“ Transfer”可能是数据库中的对象,也可能不是(在我的情况下不是)。在我看来,这种结构是RESTful的,并且可以直观地读取。

相关问题