我试图通过构建基本的纸牌游戏网络服务来学习如何构建RESTful Web服务。当我试图模拟玩家如何从牌组中抽牌时,我会陷入困境。我有/ decks资源和/卡资源。有两个问题:
1.什么资源路径应该为我绘制下一张卡?使用GET: /decks/{deckId}
似乎是错误的,因为这应该可以为我返回整个套牌。以GET: /decks/{deckId}/topcard
?
2.假设GET: /decks/{deckId}/topcard
有意义,我知道我不应该使用GET
实际从卡片顶部移除卡片,因为该操作应该是幂等的。既然如此,我们可以做到:
GET: /decks/{deckId}/topcard
- >返回topcardId(不要返回卡的实际价值。不要让客户作弊)
POST: /hands/{handId}/cards/{topcardId}
- >将之前检索到的topCardId添加到玩家手中。将卡组中的下一张卡设置为topcard资源。返回顶卡的实际值。
我遇到问题的部分是,在内部修改/decks/.../topcard
资源似乎是错误的,因为它会向另一个POST
资源请求/hands/.../cards
。这是RESTful吗?还有其他选择吗?
答案 0 :(得分:1)
我试图通过构建基本的纸牌游戏网络服务来学习如何构建RESTful Web服务。当我试图模拟玩家如何从牌组中抽牌时,我会陷入困境。我有/ decks资源和/卡资源。
简短版本:您缺少经销商资源。
您将消息发布到经销商资源,成功处理该消息的一个副作用是该平台的状态和数据模型中的玩家手牌得到更新,经销商资源将客户端重定向到......的新表示,无论你的协议的其余部分是什么。它可能是他们手牌的新表现形式,或者它可能是两张牌的代表,或其他东西。
Jim Webber在他的演讲中详细介绍Domain-Driven Design for RESTful Systems。在高层:REST的重点是客户端代码和底层服务可以独立发展(浏览器版本与服务器版本分离),因为即使底层实现需要更改,API层也能提供稳定性。
这意味着如果您将资源标识符的拼写与域模型中的实体相结合,那么您就违反了封装。在REST模型中,您操纵资源,并且作为副作用,有趣的事情发生在底层数据模型中。
尝试用四种方法操纵你的数据实体,事实真的很痛苦。 REST中的逃生舱是允许您拥有任意数量的资源。
工作(例如:向域模型发出命令)是管理资源的副作用。换句话说,资源是反腐败层的一部分。您应该希望集成域中的资源比业务域中的业务对象多得多。
简而言之,如果您需要扩展api以支持新行为,只需创建新资源即可。他们不需要匹配数据模型中的任何内容。
现在,HTTP是无状态的,因此您需要考虑服务器明确转换请求所需的信息。在"交易卡"的情况下,这可能就像清楚地识别正确的牌组和正确的牌手一样简单。您主要有三个选项:您可以将这些信息放在标识符路径的段中,放入标识符的查询参数中,或放入消息体(即表单变量)中。哪些数据在很大程度上取决于您使用的资源框架和本地设计指南。
POST /deck/{deckId}/dealer
cards=2&toPlayer={playerId}
将是一种选择。
我遇到问题的一部分是,在内部修改/decks/.../topcard资源似乎是错误的,因为它是向其他/hands/.../cards资源请求POST的副作用。这是RESTful吗?
是的 - 一直都在发生。考虑一个博客 - 您推送一个新条目,并且您对条目,订阅源以及现在将新条目列为最近帖子的其他条目进行了更改....
当您决定缓存策略时,您需要考虑这个问题;中间缓存不会知道您对一个资源的消息使一堆其他缓存条目无效。
我认为我不太了解的部分与使用HTTP for RPC有何不同。
一般来说,使REST不是RPC的原因是中间组件(缓存,反向代理)可以主动参与请求/响应交换。因为POST(以及类似的PATCH)既不安全也不是幂等,你肯定会得到RPC ish的味道。如果你使用PUT语义而不是PATCH,它会更好一点。
但请注意,即使使用POST和PATCH,中介仍然可以理解消息类型,而无需了解目标资源。
https://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.5
当我读到下属这个词时,我觉得我应该期望从中创建一个实际的资源。
不足为奇。请注意,语言在RFC 7231中更改,并且短语"从属资源"在这种情况下不再使用。
答案 1 :(得分:0)
我认为你的方式是正确的。使用POST,您可以更改Ressource的状态,这对于“rest-full”服务有效。