Reputation: 25
I'm trying to learn how to build a RESTful web service by building up a basic card game web service. I'm getting stuck when I try to model how a player draws a card from a deck. I have a /decks resource and a /cards resource. With this comes two questions:
1.What resource path should draw the next card for me? It seems wrong to use GET: /decks/{deckId}
since that should probably return the whole deck for me. Would it make sense to access the resource as GET: /decks/{deckId}/topcard
?
2.Assuming that GET: /decks/{deckId}/topcard
makes sense, I know I shouldn't use GET
to actually remove the card from the top of the deck since that operation should be idempotent. So that being the case, we could potentially do:
GET: /decks/{deckId}/topcard
-> Return topcardId (don't return the actual value of the card. Don't want the client to cheat)
POST: /hands/{handId}/cards/{topcardId}
-> Adds previously retrieved topCardId to the players hand. Sets the next card in the deck as the topcard resource. Return the actual value of the top card.
The part I have a problem with is that it seems wrong to modify the /decks/.../topcard
resource internally as a side effect to requesting a POST
to the other /hands/.../cards
resource. Is this RESTful? Are there any other alternatives?
Upvotes: 1
Views: 606
Reputation: 57289
I'm trying to learn how to build a RESTful web service by building up a basic card game web service. I'm getting stuck when I try to model how a player draws a card from a deck. I have a /decks resource and a /cards resource.
Short version: you are missing a dealer resource.
You POST a message to the dealer resource, a side effect of the successful handling of that message is that the state of the deck and the player's hand in the data model gets updated, and the dealer resource redirects the client to a new representation of ... well, whatever fits the rest of your protocol. It could be a new representation of their hand, or it could be a representation of the two cards that were dealt to them, or something else.
Jim Webber goes into detail in his talk Domain-Driven Design for RESTful Systems. At a high level: the point of REST is that the client code and the underlying service can evolve independently (browser releases are decoupled from server releases), because the API layer provides stability even when the underlying implementations need to change.
Which implies that if you are coupling the spellings of your resource identifiers with the entities in your domain model, then you are violating encapsulation. In the REST model, you manipulate resources, and as a side effect interesting things happen to the underlying data model.
Trying to manipulate your data entities with nothing but four methods and the truth is a real pain. The escape hatch in REST is that you are allowed to have as many resources as you like.
Work (ex: issuing commands to the domain model) is a side effect of managing resources. In other words, the resources are part of the anti-corruption layer. You should expect to have many many more resources in your integration domain than you do business objects in your business domain.
In short, if you need to extend your api to support a new behavior, just create new resources. They don't need to match anything in your data model.
Now, HTTP is stateless, so you need to be thinking about what information the server needs to unambiguously translate the request. In the case of "deal card", that might be as simple as clearly identifying the correct deck and the correct player. You mainly have three options: you can put that information in the segments of the identifier path, into the query parameter of the identifier, or into the message body (ie, form variables). What data goes where will largely depend on the resource framework you are using and your local design guidelines.
POST /deck/{deckId}/dealer
cards=2&toPlayer={playerId}
would be one option.
The part I have a problem with is that it seems wrong to modify the /decks/.../topcard resource internally as a side effect to requesting a POST to the other /hands/.../cards resource. Is this RESTful?
Yup -- happens all the time. Consider a blog - you push one new entry, and you have changes to the entry, the feed, the other entries that now list the new entry as a recent post....
You need to be thinking about that when you decide your caching policies; intermediary caches are not going to know that your message to one resource invalidated a bunch of other cache entries.
I suppose the part that I don't quite get is how this differs from using HTTP for RPC.
Generally speaking, what makes REST not RPC is the fact that intermediary components (caches, reverse proxies) can actively participate in the request/response exchange. Because POST (and similarly PATCH) are neither safe nor idempotent, you definitely get an RPC ish flavor. If you use PUT semantics, rather than PATCH, it's a little bit better.
However, note that even with POST and PATCH, the intermediaries still understand the message type without needing to know anything about the target resource.
https://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.5
When I read the word subordinate it makes me feel like I should expect an actual resource to be created out of this.
Not surprising. Note that the language was changed in RFC 7231, and the phrase "subordinate resource" is no longer used in that context.
Upvotes: 1
Reputation: 357
I think your way is right. With the POST you change the State of the Ressource and this is valid for a "rest-full" service.
Upvotes: 0