3 ms·
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 doma
by hartror 11y ago
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.
- vladharbuz 11y agoSome of these don't really make sense. 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.
- hartror 11y agoJust 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". http://www.thoughtworks.com/insights/blog/rest-api-design-resource-modeling 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: 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.
- vladharbuz 11y agoI agree with your comments and take them as evidence that REST is exceedingly difficult and complex for these use cases. 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.
- thetrav 11y agoI 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?