游戏的REST API

时间:2018-04-13 09:22:08

标签: angularjs spring rest web-services web

我正在开发一个网络分布式应用程序,让任何用户都可以玩Klondike(单人纸牌)游戏。我想开发一个API REST,但我不确定资源URL应该是什么样子。

在服务器上,我有“游戏”,“股票”,“浪费”,“画面”,“基础”等课程。游戏类的方法是moveFromStockToWaste,moveFromTableauToTableu ...它实现了游戏的动作。

我读到的REST API是资源URL应该看起来像名词的层次结构,而这些名词的操作(动词)是HTTP方法(GET,PUT,POST,PATCH)。 虽然moveFromTableauToTableau资源是一个动词而不是一个名词,但我不确定通过API REST将卡片从库存转移到废弃物的方法应该是这样的:

 UPDATE /player/{playerId}/game/{gameId}/moveFromTableauToTableau

其他方式我有这个画面堆积卡资源:

 URL: /player/{playerId}/game/{gameId}/TableauPile/1/ 
而不是反过来拥有的资源就像没有上翘卡和上翘卡的数量(所需的所有信息)。 然后通过删除最后一张卡来更新此tableau桩资源:

DELETE /player/{playerId}/game/{gameId}/TableauPile/1/upTurnedCard/3

然后将卡片删除到目标中,传递新的卡片套装和值:

POST /player/{playerId}/game/{gameId}/TableauPile/3/upTurnedCard

但是这样REST API就可以将卡片从画面移到废物中,这不是一个有效的动作。

2 个答案:

答案 0 :(得分:1)

我一直认为将REST API设计为一项非常不安的任务。

第二种方法在命名惯例术语中似乎更清晰,但我认为您绝不应该损害目标系统的完整性以符合这些要求。由于您允许在两个http调用中进行一次原子操作,因此它实际上不再是原子操作,并且在网络出现故障或由于某种原因任何调用失败时您将系统暴露在不可预测的状态。避免这种问题必须是首要任务。

一个想法可能是在动作收集方面进行思考。所以对于一个游戏,你有一个移动资源。然后,您可以使用一些其他请求参数(例如

)来优化移动性质
POST/players/{playerId}/games/{gameId}/moves?type=TABLEAU_TO_TABLEAU
Body: 
{
  "src": "stock",
  "dest": "waste"
}

这样你应该有足够的灵活性来处理不同类型的移动。

此外,我建议您使用复数形式进行资源命名:

播放器 - >玩家

游戏 - >游戏

所以

GET /玩家自然意味着向我提供玩家资源的所有价值

GET / players / 1表示给我玩家资源的玩家限制playerId = 1

答案 1 :(得分:1)

  

我正在开发一个网络分布式应用程序,让任何用户都可以玩Klondike(单人纸牌)游戏。我想开发一个API REST,但我不确定资源URL应该是什么样子。

Oracle:您如何将其作为网站实现?

  

在服务器上,我有游戏',' stock',' waste',' tableau','基础'课程等。游戏类的方法是moveFromStockToWaste,moveFromTableauToTableu ...它实现了游戏的动作。

要认识到的一件重要事情是,实施中的课程不重要; REST是关于操纵文档的,游戏中发生的变化是操纵"文档的副作用。

换句话说,REST API是您的游戏所穿的面具,因此它看起来像一个网站。

参见Jim Webber的演讲DDD In the Large

Klondike实际上是一个状态机;任何给定的画面都有一些有限的法律动作,每一个都会带你到一个新的位置。

因此,您可以对API进行建模的一种方式是表示每个移动的画面加可供性(链接),并且当您按照描述可能的合法移动的链接时,游戏从一个州进展到下一个州。

只有"只有"需要担心8 * 10 ^ 67左右的问题,并且对于每个人都有效地拥有所有可到达位置的图表,并按遍历顺序对它们进行排序,然后将它们全部链接在一起。

/76543210987654321098765432109876543210987654321098765432109876543210/0
/76543210987654321098765432109876543210987654321098765432109876543210/1
/76543210987654321098765432109876543210987654321098765432109876543210/2
/76543210987654321098765432109876543210987654321098765432109876543210/3

等等。

它不是impossible安排,虽然它可能不切实际,并且由于URL描述了整个游戏状态,因此玩家可以访问隐藏状态。

我建议首先尝试一种不那么复杂的方法,例如tic-tac-toe

隐藏状态相对简单,因为可以在服务器上完成当前游戏到特定种子的映射。也就是说,你发送一个POST到开始游戏终点,并生成一些随机标识符,并将随机标识符映射到种子位置,然后离开。

但是这个设计中的潜在问题是HTTP是无状态协议;当玩家请求GET /games/000/152时,服务器无法知道"客户端之前处于合法移动到位置152的位置。您可以制作URI hard to guess,但是关于它。

你可能想要的是能够确保玩家所做的动作是合法的,这意味着服务器需要跟踪游戏的当前状态,并且玩家得到一个仅查看公开信息。

最简单的HTML模型将使游戏的表示显示允许玩家的信息,以及带有合法移动列表的表单。玩家选择一个移动并提交表单,这是一个回到游戏资源的POST(直接返回到相同的资源,因为我们想要缓存失效属性)。然后,您的实施可以检查收到的移动是否合法,刷新其本地状态,并发送适当的响应。

这是我们应该考虑的基本模式;获取游戏,然后发送unsafe request来修改服务器的游戏副本。

如果您想使用远程创作方法,基本计划并非完全不同。 GET获取所显示信息的表示,客户端对该表示进行合法编辑,并将新表示PUT到同一URL。服务器验证新位置是否可以从旧位置到达,并接受移动,使用其自己的隐藏信息副本来更新玩家视图的表示。

(请注意对PUT的响应中使用的元数据;服务器应该仔细通信是否按原样采用新表示,或者服务器是否已将提议的表示转换为make它符合服务器的约束条件。

当然,您也可以使用PATCH来传达客户对代表所做的更改。

如果邮件丢失或重复,则客户端视图和服务器视图可能不对齐。因此,您可能希望让您对游戏的表示包括时钟/计时器/转弯数,以便服务器可以确定玩家移动是针对当前的游戏状态。

编辑正如Roman所说,HTTP已经内置了 validators 的概念,它允许您将域特定时钟中的数据提升到标题,以便通用组件可以理解并适当地适用于conditional requests

另一种思考游戏的方法是考虑event sourcing;客户端和服务器轮流将条目附加到log,并且通过在日志中应用事件来计算游戏本身的视图。客户端的移动将仅限于操纵开放信息的集合,服务器的移动将显示以前隐藏的信息。

因此,您可以使用Atom Pub或与其非常相似的内容将新条目写入日志。这实际上为您提供了两种不同的游戏表示 - 视图,显示您在查看画面时看到的内容,以及显示到达该点的移动的视频。

(如果你眯着眼睛,你会发现这只是一个变种"让客户选择合法的举动"。)

你可以 ,我认为,将域模型中的每个元素视为资源,并尝试设计一个API以允许客户端直接操作这些元素,但它不是。我完全清楚你从中获得了什么好处。