Thought about that as soon as I saw it returning rasters. SVG would be best offered alongside as an option; it requires more effort to use than just a png. Perhaps a 'vector' to accompany each 'image'?
Following that link, the first section on the page:
These poker sized cards have been created and hand optimized in various vector formats (.eps and .svg) using the open source .svg graphics editor Inkscape http://www.inkscape.org.
....
Generally, this means the cards are free to use (commercially and non commercially) but must be properly attributed (see "README.txt" file) and (The library itself, not your project) re-distributed only under the same license.
It was a bit fiddly but definitely wins on file size. I would have used SVG for the face cards but they really killed performance with animation unfortunately, so I went with a compressed PNG (20kb for all 3).
* You are mutating state with HTTP GET, this is an anti-pattern for a number of reasons. The common one I use with people I coach is that browsers/proxies will happily cache GET requests unless told not to, but there are a number of other reasons if you read up on REST [1].
* Being a public API in a well known domain this is a good opportunity to make the API self documenting & navigable with a hypermedia format. (eg HAL, Siren, JSON-LD) [2]
I don't see much benefit in martin fowler's example
<openSlotList>
<slot id = "1234" doctor = "mjones" start = "1400" end = "1450">
<link rel = "/linkrels/slot/book" uri = "/slots/1234"/>
</slot>
<slot id = "5678" doctor = "mjones" start = "1600" end = "1650">
<link rel = "/linkrels/slot/book" uri = "/slots/5678"/>
</slot>
</openSlotList>
Each slot now has a link element which contains a URI to tell us how to book an appointment.
Well, not really - we can only guess that by the fact that the link ends in "book".
We also don't know if we are supposed to GET, PUT, DELETE, POST.. or what data we are supposed to send to the url to actually make the booking.
I agree though I expect Fowler may argue that that is what the HTTP verb OPTIONS is for. Amundsen on the other hand likes his hypermedia more explicit and I tend to agree with him.
Clients of a hypermedia REST API are supposed to have a priori knowledge of the link relations (the "rel" attribute). The fact the rel in this example looks like a URI is sometimes used as a convention (i.e., if the API supports it, a client may do a GET against the rel value, and get back a human-readable description of the purpose of the rel).
In the human readable description of the "/linksrels/slot/book" link relation, information should be given about what generally can be done with such links (like if GET or POST is supported, etc). This allows you to build your client applications. The value of the actual link (the 'uri' attribute) should be completely opaque to the client.
I agree. However, this is the first API I've seen where a mutable GET actually makes sense. Drawing a card is definitely a GET. How would you do it instead?
Could each draw return a draw_hash, that is usable only once? Not only could you then have idempotent draws, you could easily embed it as hypermedia,a previous hash could be sent to a hand_history to return an array of point in time data
I'm not questioning that; I was questioning the statement '"action" parameter is pretty non-RESTful'. If URLs are opaque, why is it non-RESTful? Or is the point that if you're using query-string parameters, then by definition you're using a method that's supposed to be safe or idempotent?
If you used different HTTP methods, you'd already know which one to use, and don't need the action parameter. So the usage of the "action" parameter usually implies that that requests are all the same method. And if we don't want to violate the HTTP standard, that method must be neither GET/HEAD, nor PUT nor DELETE (as surely some actions are non-idempotent).
In other words, an action parameter which is actually used and which doesn't violate the HTTP standard, well, that almost certainly means that all requests are POST requests.
However, if all requests are POST, no matter if they are side-effect-free or not, no matter if they are idempotent or not, then this is not very REST-like.
Note that it is not important whether you think this argument does or doesn't holds for your particular API. My point is that this whole judgement is solely about HTTP methods, and has nothing to do with URLs being opaque.
> If you used different HTTP methods, you'd already know which one to use, and don't need the action parameter.
But the examples given by anilgulechas were 'action=draw' and 'action=shuffle'. Neither are idempotent, let alone safe, so presumably the only method to use in either case would be POST (notwithstanding anilgulecha's suggestion of a PUT).
So we need to distinguish between POSTs requesting a draw, and POSTs requesting a shuffle. Two options:
a) indicate it in the POST's body
b) indicate it in the URL.
If we go for (b), the query string seems as good a place as any.
What have I got wrong? Where would this violate REST (or the HTTP spec)?
I see where you're coming from ("I'm drawing / taking / GETting some cards"), but drawing cards is not an idempotent action. I would implement it as a POST.
I think it's more of a terminology thing, rather than 'GET me a card' you could 'POST remove 2 cards from the deck' and the side effect is the response tells you which cards were deleted.
But this kind of bike shedding drives me mad because oh my lord who gives a crap just build software and document it properly.
Same here. Working on a large codebase where people "just build software and document it properly" without following standards is not fun. Not to mention that frequently people end up shortening that to "just build software". It's better to get in the habit of following good standards even on small projects before bad habits form.
Why conform to arbitrary conventions when they don't make sense? Personally I think the best reason to conform to REST is because the user expects a "good" api to conform. Other then that is there any hard reason as to why it's "better" to strictly follow REST or even follow it at all?
Is an api that is consistent, fast and documented well, but uses only GET requests for everything including state changes really a horrible api?
> Is an api that [...] uses only GET requests for [...] state changes really a horrible api?
Yes, it is. Because HTTP clients (including browser) rely on the common method properties as defined by the HTTP standard (GET having no side effects, PUT being idempotent, etc.). The simplest example is caching / proxying, but there is other behaviour.
I strong recommend acutally taking a look at the HTTP standard. The RFCs such as RFC 7231 are well organized and human readable. For the definition of the HTTP verbs, see:
RFC 7231 Hypertext Transfer Protocol (HTTP/1.1): Semantics and Content
4.2 Common Method Properties
I agree with the spirit of your post, but using the right HTTP verbs can have real, actual consequences because of how some caches and clients behave. You're more likely to accidentally send multiple requests or get stale data when you're using GET.
As others have pointed out the HTTP verbs have meaning at a protocol level, trying to match a verb based on its English meaning is fraught with problems. Not least of which is the proxy problem I pointed out in my original comment.
That's not what idempotent means. It doesn't mean it produces the same side effects every time, it means multiple calls are equivalent to a single call.
It is acceptable for a client to retry a request that failed if it is a GET. This could happen if the server got your request but the response got lost, in which case you can't count on the deck having the right number of cards.
If it supported the idea of multiple players, keeping track of what cards each player has, and facilitating passing cards between players; it could be a cool backend for lots of different card games.
I wonder if you could do most of this cryptographically. If you did, you could make a client that could do all of this peer-to-peer. I think you would just need the following to make a wide range of games (many popular ones, perhaps most?):
1. Client can produce a signature that it drew the k'th card from the deck for any k.
2. Client can produce a signature that the k'th card is X if it drew the k'th card.
3. Client can produce a signature that card X came from any arbitrary set of card indices containing k if it drew the k'th card. (This is the hardest one.) If it's easier, you could get most of this even restricting it to sets of cards that the client has drawn.
With just that, I bet you could make a protocol for most card games where no one can cheat, where the central server's role is only to give out information about k'th card one and only one time. Certainly it's enough for blackjack, most forms of poker, hearts, and go fish. Anyone have a game that would be difficult? Maybe one where hidden cards get passed from player to player.
I think it was just a fun side project. But as to how it could be used.. just a few weeks ago we were at a hackathon and built a quick poker texas holdem game. A library like that (arguably a bit more comprehensive) would have saved us a few hours.
Was it just a texas hold em ? Or a variation of it ? I assume being a hackathon it wasn't a vanilla texas hold em.
Could you provide some more details and maybe the code ? After seeing this I'm interested to know what else you've done.
So we wanted to learn/play with react native. The project idea was to play a hand of poker online randomly against someone in less than 30 seconds. The fun part is you can only fold or go all-in : )
I like the website design but shuffling cards is extremely trivial to code. Also cards are mostly used for gambling games and it's a huge security hole to use a third party api for that unless it's from a very trustworthy source.
One maybe useful thing about this api is the card images, but there are also probably plenty of decks in the public domain.
> Also cards are mostly used for gambling games and it's a huge security hole to use a third party api
Depends. If you're writing a game you wanted the player to trust you might want to use an external shuffling service so you can easily show proof-of-deck after the game is over.
Of course, you could do this simply by giving the player a cryptographic hash of the shuffled deck beforehand, e.g. SHA-256(5H,4D,AS...)
I've worked as a developer for online gambling games for 6 years. We never shuffled the deck of cards. Instead, as player requests another card(s), they are generated using hardware RNG and returned to player. Deck only knows which cards are left in it, but their order is undefined until that call to RNG.
You are correct. As the matter of fact, a bunch of games in majority of cases needed only the next card from the deck, that's why in our heads we almost always thought of "not shuffling at all".
How is that better? You just don't want to spend the time to shuffle a deck if only a few cards will be used? Or you are worried someone might cheat by being able to read card order ahead of time?
But how are you shuffling the cards, and how are you identifying unique shuffled decks?
It looks like the deck_id is 12 characters, numbers or lower-case letters. That gives a range of 36^12 or around 4.7 * 10^18. The total range of a physical deck of shuffled cards is 52! or around 8 * 10^67.
It's possible I have misunderstood what deck_id is for.
Wow. I never thought this could be an API. Really good work. I remember I spent a lot of time developing a class that deals with a deck of cards, shuffle and associate the card with a png.
While this looks to me like a pretty clean and straightforward API, it's definitely not a REST API (not that it claims to be):
* The API doesn't really follow HTTP. It allows GET for state-modifying actions, which breaks assumptions that could be made by browsers, client libraries, caches, and proxies. Also, the "success" field seems fishy; a 200 response code is the usual HTTP way to indicate success.
* The API is not resource-oriented; the URLs "shuffle" and "draw" are verbs that describe the action to take. In a "real" REST API, URLs define conceptual resources (nouns), and you interact with the API by interacting with those resources.
* The API does not use hypermedia.
Hypermedia and HTTP compliance are discussed elsewhere in this thread, but I wonder if others have an opinion on the fact that the API isn't resource-oriented.
This "resource-oriented" rule has always bugged me about REST APIs. My impression has been that REST advocates claim that pretty much every API can and should be implemented with a CRUD-like interface (where the entire API consists of performing GET, POST, PUT, and DELETE on a conceptual set of resources), but it seems like that would be really awkward for this "deck of cards" use case. Is there value in trying to use resources here? What might it look like?
I guess shuffles and draws should be their own resources, and you POST to it to do that action? You'd then keep a table of shuffle/draw events, which mutate the deck as a side effect.
I get it. I had an idea to make a "shuffled-copy" or a new deck with one less card, made from the original deck. Than you can theoretical rewind your shuffle process, since it's a chain of immutable decks. But I'm afraid that will really consume too much storage for a rather unimportant thing, at least in this case :) .
You could shuffle in a deterministic way, using a smallish seed, and store a list of those seeds which would cut down on storage. I realise that you probably wouldn't want to do this if you're trying to recreate Vegas, but it's an interesting challenge to mull over nonetheless :)
Resource oriented and its implication of nouns as opposed to verbs doesn't have to equal CRUD. I can see a case for bending the nouns rule of thumb in this domain, for example I might have an api like so:
POST /decks : returns a url to a new deck
GET /decks/<id> : returns a deck
POST /decks/<id>/draw : returns a url to a card
POST /decks/<id>/shuffle : returns a url to the deck
GET /cards/<id> : returns a card drawn from a deck
The draw/shuffle verbs arguably could be implemented like this:
POST /cards : returns a url to a card (post body having deck id)
POST /shuffles : returns a url to the deck (post body having deck id)
The cards POST makes a lot of sense, now that I look at it I think I would use that interface. And you could argue that the shuffles resource makes sense as at some point you may want to record and share when someone shuffles the deck.
POST /decks/<id>/draw : returns a url to a card
POST /decks/<id>/shuffle : returns a url to the deck
Are you adding a "draw" to deck <id>?
POST /cards : returns a url to a card (post body having deck id)
POST /shuffles : returns a url to the deck (post body having deck id)
Are you creating a card or a shuffle?
Here's how things should be, in my opinion:
DELETE /deckCard/<deckId>
This removes a card from an abstract entity representing the relation between decks and cards. Thus, it draws a card and returns it, sort of like popping something off a stack.
PUT /decks/<id> with body {shuffle: true}
This edits the abstract "shuffle" attribute of deck <id>, shuffling the deck. This is indeed odd, but I'm afraid it's the best you can do for a mutating request. I would recommend a non-mutating request that makes a new deck out of an old deck, perhaps using "source" as an abstract attribute.
POST /decks with body {source: <oldId>}
It just goes to show that while REST is a good standard for CRUD operations, and is surprisingly extensible for non-CRUD operations, it can get confusing and become a real pain. Should one just deal with it or move to e.g. RPC? I haven't figured this out.
Just because a thing, such as a draw or a shuffle isn't a physical thing doesn't mean it cannot exist as resource. Programming is all about creating abstractions, so why cannot I create a shuffle or a draw resource? I could even record them and share them on their own endpoints for clients to view.
Commenting directly on you suggestions:
DELETE /deckCard/<deckId>
This means each DELETE on this url would result in a different deck state which isn't idempotent as DELETE is mean to be.
PUT /decks/<id> with body {shuffle: true}
Same with this, the resource would end up in a new state each time making it unsafe to do repeatedly as the HTTP spec says.
I think the issue is REST is taught with a CRUD view point and people have difficulty thinking about it in other ways. Also the English meanings of the HTTP verbs get confused with their HTTP meanings which doesn't help.
I liked this blog post which talks about the concept of "REST without PUT".
edit: you've edited you comment since I started my reply:
I like your idea of replacing shuffle with a new deck:
POST /decks with body {source: <oldId>}
You could then do things like lock the source deck which would make it easier to implement a multi-client system where you cannot draw from a deck until you have been informed it has been shuffled.
I would approach it from a little further away conceptually.
A deck only makes sense in the context of a game, a draw only makes sense in the context of moving the card from the deck to some other container (hand, discard pile, arbitrary pile on the table).
I also like to model games as sequential actions (because that's how they work) so my API would be more like:
GET /game/<id>/turn/<index>/decks/<id>/card/<index> <- 1 or 0 for top card, other numbers to view more than one
Then your draw action is a move the card from the deck to one of the other places, either with a POST to the new place, that redirects you to the next turn of that place, or with a PUT to the card itself if you have some "location" field on the card that can be updated.
The question that strikes me though, is whether it makes sense at all for a client to be controlling the draw in a game of CaH, as it's not an optional step.
Why not just have the model automatically put cards back in the players hands when they make their moves?
I like my REST interfaces, but they only really fit CRUD-like situations. Sometimes, you will want to be less restful to optimize for some real world issue, most likely latency.
I suppose it is a bit like de-normalizing your database for performance.
For a situation like this, I would keep it as restful as practically possible. Since the shuffle mutates the state, it should be a post/put. Since it doesn't create a new resource,you could argue it should be put, but you don't have new data anyway, so the point is kind of moot.
I'd probably collect my custom verbs behind a common path to make it more clear, like
/api/decks/mydeckid/verbs/shuffle
Or to make it stand out more:
/api/decks/mydeckid?verb=shuffle
The response would use http error/success codes like any rest interface.
SOAP APIs tend to use POST even for readonly methods, and tend to use aggressively validated XML that's much harder to write by hand than typical "REST" JSON.
I'm sure why using POST for readonly methods is a problem in the browser. It potentially messes with caching, but it should still function correctly. (Granted, this is probably a poor design design decision, but has nothing to do with correct functionality.)
As far as constructing the XML, you should be able to use something like xmlbuilderjs[0]. That said, I completely agree that dealing with REST APIs in the browser is far more practical.
I'm not sure that a CRUD like interface would be best for something like this. In addition, as this is very much an API and the returned JSON changes depending on the action called on the resource, this looks to me like the ideal candidate to create a custom media type for. With that option open, we can simply define our own request verbs like so:
SHUFFLE /api/deck/<deck-id>
DRAW /api/deck/<deck-id>?count=2
Things become a lot simpler to use, document and implement.
I'd actually take advantage of the custom media-type option and return something much more succinct:
DRAW /api/deck/<deck-id>?count=2
200 OK
8♣
Have the response body be UTF-8 and use the card face runes in the response. Nice and simple.
You dont necessarily have to map your REST API to existing HTTP verbs and media types - in fact the real benefit in a use case like this is that you can implement something appropriate
Both REST AND HTTP allow you to specify your own verbs and media types! What I was suggesting was that the semantics of the API could be better expressed as its own media-type with specific semantics rather than try to force the existing HTTP 1.1 semantics on it.
Think WebDAV; specify the API via an RFC like document and implement it that way the end result is not only easier to use, document and implement, other providers could implement compatible API implementations.
Seriously, has anyone here actually READ Fieldings paper?
But it wasn't hard to find something about standard methods and media types.
> REST enables intermediate processing by constraining messages to be self-descriptive: interaction is stateless between requests, standard methods and media types are used to indicate semantics and exchange information, and responses explicitly indicate cacheability.
Thank you for your honesty. It's refreshing and I appreciate it.
I'm not sure if your response is an attempt at a counter argument, but the line "... standard methods and media types are used to indicate semantics and exchange information, and responses explicitly indicate cacheability" is exactly the point I'm making.
If the original author was keen to make their API RESTful (which I'm not particularly sure they are. Aside from the couple of minor issues people have already raised, there is nothing wrong with a JSON API served over HTTP. It's just not RESTful), they would standardize their media-types (by registering them with IANA) and document their custom HTTP verbs via a RFC. That is what is required to be truely RESTful.
In the example I gave, showed that by adhering to the principles of REST, they could actually simplify their API dramatically whilst allowing others to lean on their work (by implementing their own services that use their newly registered media-types).
Again, all this is documented in Fieldings dissertation. It is dense reading and very academic, but it's worth reading. I personally found it very enlightening.
The original API wasn't REST and wasn't claiming to be either! The commenter is right, this is a clear case for an RPC style protocol. One using HTTP (and robustly!) makes client creation easier, but it's still RPC and doesn't need to pretend to be REST.
145 comments
[ 3.3 ms ] story [ 130 ms ] threadhttps://github.com/crobertsbmw/deckofcards/blob/master/stati...
> After two weeks, if actions have been made on the deck then we throw it away.
Might be "if no actions"?
Edit: Could be an excellent idea - 8 of Clubs is:
* 28kb as a PNG.
* 14kb as an SVG
* 4kb as a gzipped SVG
But they seem familiar. I can't help but wonder, are they infringing on any copyrights?
These poker sized cards have been created and hand optimized in various vector formats (.eps and .svg) using the open source .svg graphics editor Inkscape http://www.inkscape.org.
....
Generally, this means the cards are free to use (commercially and non commercially) but must be properly attributed (see "README.txt" file) and (The library itself, not your project) re-distributed only under the same license.
It was a bit fiddly but definitely wins on file size. I would have used SVG for the face cards but they really killed performance with animation unfortunately, so I went with a compressed PNG (20kb for all 3).
A few comments/suggestions:
* You have DEBUG = True in your production Django config. (eg. http://deckofcardsapi.com/api/)
* You are mutating state with HTTP GET, this is an anti-pattern for a number of reasons. The common one I use with people I coach is that browsers/proxies will happily cache GET requests unless told not to, but there are a number of other reasons if you read up on REST [1].
* Being a public API in a well known domain this is a good opportunity to make the API self documenting & navigable with a hypermedia format. (eg HAL, Siren, JSON-LD) [2]
[1] http://martinfowler.com/articles/richardsonMaturityModel.htm...
[2] http://sookocheff.com/posts/2014-03-11-on-choosing-a-hyperme...
Other than learning, what's the benefit here?
Martin Fowler does a good job explaining it (http://martinfowler.com/articles/richardsonMaturityModel.htm...).
As does Mike Amundsen (http://www.infoq.com/presentations/Building-Hypermedia-API).
We also don't know if we are supposed to GET, PUT, DELETE, POST.. or what data we are supposed to send to the url to actually make the booking.
In the human readable description of the "/linksrels/slot/book" link relation, information should be given about what generally can be done with such links (like if GET or POST is supported, etc). This allows you to build your client applications. The value of the actual link (the 'uri' attribute) should be completely opaque to the client.
I agree. However, this is the first API I've seen where a mutable GET actually makes sense. Drawing a card is definitely a GET. How would you do it instead?
Sometimes RPC-style interfaces like that are ok, but don't pretend that they are RESTful.
Also PUTs are supposed to be idempotent, so don't use a PUT for this.
In other words, an action parameter which is actually used and which doesn't violate the HTTP standard, well, that almost certainly means that all requests are POST requests.
However, if all requests are POST, no matter if they are side-effect-free or not, no matter if they are idempotent or not, then this is not very REST-like.
Note that it is not important whether you think this argument does or doesn't holds for your particular API. My point is that this whole judgement is solely about HTTP methods, and has nothing to do with URLs being opaque.
But the examples given by anilgulechas were 'action=draw' and 'action=shuffle'. Neither are idempotent, let alone safe, so presumably the only method to use in either case would be POST (notwithstanding anilgulecha's suggestion of a PUT).
So we need to distinguish between POSTs requesting a draw, and POSTs requesting a shuffle. Two options:
a) indicate it in the POST's body
b) indicate it in the URL.
If we go for (b), the query string seems as good a place as any.
What have I got wrong? Where would this violate REST (or the HTTP spec)?
I see where you're coming from ("I'm drawing / taking / GETting some cards"), but drawing cards is not an idempotent action. I would implement it as a POST.
But this kind of bike shedding drives me mad because oh my lord who gives a crap just build software and document it properly.
Is an api that is consistent, fast and documented well, but uses only GET requests for everything including state changes really a horrible api?
Yes, it is. Because HTTP clients (including browser) rely on the common method properties as defined by the HTTP standard (GET having no side effects, PUT being idempotent, etc.). The simplest example is caching / proxying, but there is other behaviour.
I strong recommend acutally taking a look at the HTTP standard. The RFCs such as RFC 7231 are well organized and human readable. For the definition of the HTTP verbs, see:
https://tools.ietf.org/html/rfc7231#section-4.2Looking at the cards in your hands, if the server maintains your hand state, would be a GET though.
DELETE /api/<deck-id>/top?count=2
------
200 Ok
8♣
10♥
> Idempotence refers to the state of the system after the request has completed
> ...
> The key bit there is the side-effects of N > 0 identical requests is the same as for a single request.
http://stackoverflow.com/questions/4088350/is-rest-delete-re...
2. GET makes sense here. If anything, it would be a PATCH. But it's silly to get bogged down in details.
Those "details" are quite important, as already explained in several other comments:
https://news.ycombinator.com/item?id=9523225
https://news.ycombinator.com/item?id=9523106
https://news.ycombinator.com/item?id=9523075
https://news.ycombinator.com/item?id=9523066
https://news.ycombinator.com/item?id=9525568
https://news.ycombinator.com/item?id=9462184
Would be interesting to hear if some of the issues raised in the previous submission were fixed or updated.
You can do that via https://help.github.com/articles/remove-sensitive-data/, but once it's been cloned, the file is of course out of the toothpaste tube so to speak :-)
1. Client can produce a signature that it drew the k'th card from the deck for any k.
2. Client can produce a signature that the k'th card is X if it drew the k'th card.
3. Client can produce a signature that card X came from any arbitrary set of card indices containing k if it drew the k'th card. (This is the hardest one.) If it's easier, you could get most of this even restricting it to sets of cards that the client has drawn.
With just that, I bet you could make a protocol for most card games where no one can cheat, where the central server's role is only to give out information about k'th card one and only one time. Certainly it's enough for blackjack, most forms of poker, hearts, and go fish. Anyone have a game that would be difficult? Maybe one where hidden cards get passed from player to player.
Nit: drawing from an empty deck does not throw an error: > curl http://deckofcardsapi.com/api/draw/i763hn8lcg0e/ {"remaining": 0, "cards": [], "deck_id": "i763hn8lcg0e", "success": true}
As does drawing a comically large number of cards: > http://deckofcardsapi.com/api/draw/vzlem7q4jhna/?count=10000... (...) "success": true}\n
1. An example of how this could be used.
2. How to do something other than just shuffling the cards.
1. An example of how this could be used.
2. How to do something other than just drawing the cards.
One maybe useful thing about this api is the card images, but there are also probably plenty of decks in the public domain.
Depends. If you're writing a game you wanted the player to trust you might want to use an external shuffling service so you can easily show proof-of-deck after the game is over.
Of course, you could do this simply by giving the player a cryptographic hash of the shuffled deck beforehand, e.g. SHA-256(5H,4D,AS...)
But how are you shuffling the cards, and how are you identifying unique shuffled decks?
It looks like the deck_id is 12 characters, numbers or lower-case letters. That gives a range of 36^12 or around 4.7 * 10^18. The total range of a physical deck of shuffled cards is 52! or around 8 * 10^67.
It's possible I have misunderstood what deck_id is for.
The model stores the state of the deck, including things like order and remaining cards and how many "decks" of 52 cards are in play.
Would like an option to set parameters of a deck. Some card games use only 8 cards from a set and not the whole 13.
I would use this API in the future.
* The API doesn't really follow HTTP. It allows GET for state-modifying actions, which breaks assumptions that could be made by browsers, client libraries, caches, and proxies. Also, the "success" field seems fishy; a 200 response code is the usual HTTP way to indicate success.
* The API is not resource-oriented; the URLs "shuffle" and "draw" are verbs that describe the action to take. In a "real" REST API, URLs define conceptual resources (nouns), and you interact with the API by interacting with those resources.
* The API does not use hypermedia.
Hypermedia and HTTP compliance are discussed elsewhere in this thread, but I wonder if others have an opinion on the fact that the API isn't resource-oriented.
This "resource-oriented" rule has always bugged me about REST APIs. My impression has been that REST advocates claim that pretty much every API can and should be implemented with a CRUD-like interface (where the entire API consists of performing GET, POST, PUT, and DELETE on a conceptual set of resources), but it seems like that would be really awkward for this "deck of cards" use case. Is there value in trying to use resources here? What might it look like?
Here's how things should be, in my opinion:
This removes a card from an abstract entity representing the relation between decks and cards. Thus, it draws a card and returns it, sort of like popping something off a stack. This edits the abstract "shuffle" attribute of deck <id>, shuffling the deck. This is indeed odd, but I'm afraid it's the best you can do for a mutating request. I would recommend a non-mutating request that makes a new deck out of an old deck, perhaps using "source" as an abstract attribute. It just goes to show that while REST is a good standard for CRUD operations, and is surprisingly extensible for non-CRUD operations, it can get confusing and become a real pain. Should one just deal with it or move to e.g. RPC? I haven't figured this out.Commenting directly on you suggestions:
This means each DELETE on this url would result in a different deck state which isn't idempotent as DELETE is mean to be. Same with this, the resource would end up in a new state each time making it unsafe to do repeatedly as the HTTP spec says.I think the issue is REST is taught with a CRUD view point and people have difficulty thinking about it in other ways. Also the English meanings of the HTTP verbs get confused with their HTTP meanings which doesn't help.
I liked this blog post which talks about the concept of "REST without PUT".
http://www.thoughtworks.com/insights/blog/rest-api-design-re...
edit: you've edited you comment since I started my reply:
I like your idea of replacing shuffle with a new deck:
You could then do things like lock the source deck which would make it easier to implement a multi-client system where you cannot draw from a deck until you have been informed it has been shuffled.You can create new resources, just as I have, it just doesn't make sense to "POST /cards" when you're not making a new card at all.
A deck only makes sense in the context of a game, a draw only makes sense in the context of moving the card from the deck to some other container (hand, discard pile, arbitrary pile on the table).
I also like to model games as sequential actions (because that's how they work) so my API would be more like:
GET /game/<id>/turn/<index>/decks/<id>/card/<index> <- 1 or 0 for top card, other numbers to view more than one
Then your draw action is a move the card from the deck to one of the other places, either with a POST to the new place, that redirects you to the next turn of that place, or with a PUT to the card itself if you have some "location" field on the card that can be updated.
The question that strikes me though, is whether it makes sense at all for a client to be controlling the draw in a game of CaH, as it's not an optional step. Why not just have the model automatically put cards back in the players hands when they make their moves?
I suppose it is a bit like de-normalizing your database for performance.
For a situation like this, I would keep it as restful as practically possible. Since the shuffle mutates the state, it should be a post/put. Since it doesn't create a new resource,you could argue it should be put, but you don't have new data anyway, so the point is kind of moot.
I'd probably collect my custom verbs behind a common path to make it more clear, like
Or to make it stand out more: The response would use http error/success codes like any rest interface.As far as constructing the XML, you should be able to use something like xmlbuilderjs[0]. That said, I completely agree that dealing with REST APIs in the browser is far more practical.
[0] https://github.com/oozcitak/xmlbuilder-js/
SHUFFLE /api/deck/<deck-id>
DRAW /api/deck/<deck-id>?count=2
Things become a lot simpler to use, document and implement.
I'd actually take advantage of the custom media-type option and return something much more succinct:
DRAW /api/deck/<deck-id>?count=2
200 OK
8♣
Have the response body be UTF-8 and use the card face runes in the response. Nice and simple.
You dont necessarily have to map your REST API to existing HTTP verbs and media types - in fact the real benefit in a use case like this is that you can implement something appropriate
Think WebDAV; specify the API via an RFC like document and implement it that way the end result is not only easier to use, document and implement, other providers could implement compatible API implementations.
Seriously, has anyone here actually READ Fieldings paper?
But it wasn't hard to find something about standard methods and media types.
> REST enables intermediate processing by constraining messages to be self-descriptive: interaction is stateless between requests, standard methods and media types are used to indicate semantics and exchange information, and responses explicitly indicate cacheability.
https://www.ics.uci.edu/~fielding/pubs/dissertation/rest_arc...
I'm not sure if your response is an attempt at a counter argument, but the line "... standard methods and media types are used to indicate semantics and exchange information, and responses explicitly indicate cacheability" is exactly the point I'm making.
If the original author was keen to make their API RESTful (which I'm not particularly sure they are. Aside from the couple of minor issues people have already raised, there is nothing wrong with a JSON API served over HTTP. It's just not RESTful), they would standardize their media-types (by registering them with IANA) and document their custom HTTP verbs via a RFC. That is what is required to be truely RESTful.
In the example I gave, showed that by adhering to the principles of REST, they could actually simplify their API dramatically whilst allowing others to lean on their work (by implementing their own services that use their newly registered media-types).
Again, all this is documented in Fieldings dissertation. It is dense reading and very academic, but it's worth reading. I personally found it very enlightening.