PUT /teams/1/players/1/
我现在想把球员换到另一个队伍,我该怎么做呢?
PUT /teams/1/players/1/
/players
和 /teams
都作为顶级资源。使用玩家上的属性来控制玩家所在的队伍。然后您可以通过 PUT
玩家并更新新的团队值来更新玩家的团队。GET /team-memberships?teamId=7
或 GET /team-memberships?playerId=2
。您可以在此资源上发布和删除以添加和删除球员。HTTP PUT
或HTTP PATCH
(如果仅需执行部分更新,则使用后者)。但是,像PUT /teams/1/players/1?moveToTeam=2
这样的结构存在一些语义问题,即用请求体中找到的负载替换当前表示。可选的查询参数是您在服务器端调用的方法,以将玩家从团队1移动到团队2。然而,HTTP PUT
是幂等操作,这基本上意味着如果您执行相同的语句两次,则会产生相同的效果。但是,由于您正在从团队1中删除玩家并将当前用户的数据复制到新位置,因此调用相同的方法违反了HTTP PUT
的幂等性质,因为连续调用将失败,因为没有可用的/teams/1/players/1
资源或者没有可用的玩家内容,因此移动玩家的内容也将设置为空。因此,我不建议使用HTTP PUT
。
也许DELETE /teams/1/players/1?moveToTeam=2
是最接近单个HTTP操作的方式,可以将一个玩家从一个团队移动到另一个团队。此请求成功地从团队1中删除了玩家,在调用之后不应再有该资源(幂等性),因此进一步的调用不会改变资源。该操作应返回一个200 OK
,其中包括球员实体的新状态,其链接现在应指向其新位置。HTTP DELETE
还允许移动资源,根据规范,尽管规范规定此资源在执行操作后不应可访问。
DELETE方法请求源服务器删除由Request-URI标识的资源。该方法可能被源服务器上的人为干预(或其他手段)覆盖。即使从源服务器返回的状态代码表明已成功完成操作,客户端也无法保证已执行该操作。但是,服务器不应指示成功,除非在给出响应时,它打算删除资源或将其移动到不可访问的位置。
如果响应包含描述状态的实体,则成功的响应应该是200(OK);如果尚未执行操作,则为202(已接受);如果已执行操作但响应不包括实体,则为204(无内容)。(来源)
因此,我认为如果您尝试完全遵循RESTful,这个操作有点冒险。
因此,我建议将操作拆分为原子单元:
GET /teams/1/players/1
)DELETE /teams/1/players/1
)POST /teams/2/players
)GET /teams/1/players/1
的用户创建重定向 (301 Moved Permanently
),以便他们自动转发到GET /teams/2/players/n
,其中n
是球员的新ID。每个操作都遵循HTTP规范中定义的规则,因此将请求分成原子部分应该没问题。
更新
尽管我同意 @EricStein 的观点,即将玩家分离到自己的资源中,因为这会极大地简化从团队1移动玩家到团队2的操作,但我也看了一下 PATCH
方法,它似乎比 DELETE
或将移动拆分成多个原子请求更合适。
PATCH
经常被误解为部分更新,只发送资源属性的新值到服务器,实际上并非如此。 PATCH
的结果可能相等,但是 PATCH
发送必要的步骤,服务器必须执行这些步骤才能将资源从一个状态转换为新状态。规范明确指出:
特别是最后引用的那一行指出它可能会产生副作用并创建新资源。因此,如果由于任何原因您无法更改您的模型,则PATCH
可能是将球员从一支团队移动到另一支团队的最佳方式。该方法允许您发送服务器必须执行的必要步骤,以创建已移动球员的新资源,删除旧表示并在单个请求中建立永久前向到新资源。但是,此操作既不安全也不幂等!
POST
的玩家是哪个被DELETE
了(并创建#301
规则)? - Robert/teams/1/players/1
现在变成了 /teams/2/players/n
,因此移动资源的用户必须通知服务器有关“移动”的信息。这可以通过将#2与#3交换并向 DELETE
操作添加一个参数来解决,该参数通知服务器应创建重定向到 #2 返回的位置(尽管我认为这有点违反删除语义),或者发送一个 PUT
请求作为#4,创建指向已移动资源的重定向。 - Roman Vottner做类似于POST /teams/1/players/5/transfers
这样的事情怎么样?这将创建一个“团队球员转会”的效果。在url中提供了Team
和Player
的id
,而正文可以是{ new_team_id: 2 }
之类的东西。然后服务器可以以任何它喜欢的方式执行“转移”。
“转移”可能是数据库中的对象,也可能不是(在我的情况下不是)。这种结构对我来说似乎是符合RESTful的,而且阅读起来也很直观。