views:

689

answers:

9

How would you model a turn-based game server as a RESTful API? For example, a chess server, where you could play a game of chess against another client of the same API. You would need some way of requesting and negotiating a game with the other client, and some way of playing the individual moves of the game.

Is this a good candidate for a REST (RESTful) API? Or should this be modelled a different way?

A: 

I think you could model it RESTfully. Implementing it will be more difficult, because you'd either need a comet)-esque solution or you'd have to be polling the server at a relatively short interval via AJAX.

In terms of how you'd expose a RESTful interface, I'd say that you need a playing board with coordinates, pieces that can occupy those coordinates, and actions that alter those coordinates.

When a player makes a move, a new action would be created. After validating to make sure it's allowed, you'd update the status of the game, then render whatever response is needed to update the UI.

So that's basically how I'd model it. The implementation side is what I'd consider the bigger difficulty here though.

nakajima
Your "comet" link is not working. The closing paren of the URL has somehow dropped off into the text.
Will Wagner
A: 

What are the resources you're trying to model? I would seem to have four: You, your opponent, the particular game (session, instance) and the game board state. So it would start with something like

/game
/game/gameID/gamer/gamerID
/game/gameID/board

we've got a good intro/overview on InfoQ.

Charlie Martin
Agree with Charlie, start with definition of resources. Except of those already mentioned, I would consider adding a MOVE resource, too.
Milan Novota
This is not a RESTful API if you are defining more URIs than just an entry point. If you define URIs for resources as part of your API, you are violating a constraint of REST.
Wahnfrieden
A: 

I don't think it's all that complciated, Nakajima. You'd pass data, say in JSON, for the board position, for the moves, and with a token for who has the next move. It'd be exactly like playing by mail.

You start by going to the game and looking for a partner, so

/game/

gives you a list of people waiting. when you come in, if there is no one waiting you get a game ID; otherwise you pick someone waiting and get the game ID they have.

/game/gameID

shows you the board. You need something to set up the decision of who plays white, i'll leave that as an exercise. The GET operation gives you the board, so a POST sends a move; if you don't have the move you get an error. You find the result by the next GET.

Hell, in this model I'm not even using the gamer ID, although it might be good so no one can sneak into the game as a kibitzer.

Charlie Martin
This is not RESTful. The client should not have to assemble URIs or know anything about their structure. This violates a constraint of REST.
Wahnfrieden
Sorry, you're mistaken. The Wikiedia article is good, or you could read Roy Fielding's dissertation.
Charlie Martin
Fielding agrees the Wikipedia article is in poor condition. It's preferable to provide entire URIs in hypertext in the response - gzip makes the extra bandwidth used negligible next to the added clarity. Anyway, you can have URI templates inside your responses, but you cannot have these URIs specified as part of your API if you want to call the API RESTful. So the client can't know about /game/gameID, just that there are fields in the /game/ response which give URIs for different games.
Wahnfrieden
A: 

So your thought is that instead of making the actions a first class object, each move would be treated as an update of the game itself? It's certainly a different way to do it, though I think I'd prefer to split the action object out into its own first class entity for a couple reasons. The biggest reason is that I believe it's more testable. Whether or not a move is valid could live in the action object, instead of needing to worry about the board being in a valid state at all times. Granted, I don't know what either approach would entail, but this feels better to me.

The other reason, which you can totally refute via YAGNI, is that a first class action object would provide a history of moves. Interesting perhaps, but unless a requirement, is a moot point.

nakajima
+1  A: 

I'm thinking something like:

/game/<gameID>/move/<moveID>

as far as the basic resources are concerned. I'm not sure how to handle the "has the other player moved yet?" idea, though. I've thought about simply having the GET request block until the move is played--i.e. my client would PUT the coordinates of my move to

/game/13/move/1

and then would GET

/game/13/move/2

The server would not respond immediately, but keep the connection open until the other player moved (i.e. PUT to that location). Is this what nakajima is referring to as "comet-esque"?

Charlie, I'm not quite sure what you meant by the "token" for whose turn it is--does this solve the same problem without the need for polling or a blocking connection?

For player IDs, does it make sense to model those as a resource in part of the URL? I was planning to simply use HTTP user authentication (where the user/pass is sent as part of every request). You could still GET most resources without authentication, but if you tried to, say,

PUT /game/13/move/2

it would give you a permission denied error if you didn't have the correct credentials for that game.

Ross
nice, I might suggest a temporary error, or even a 404, and have the client re-poll after x seconds, the issueswith this are caching of get requests, and timeouts from the server or client (browser?).
Tracker1
+1  A: 

OKay, the basic idea of REST is that you're transferring the state; you want to have little or no "session state" on the server. So you wouldn't want to use session state and a keepalive, which is what Comet does. But think about the example of a play-by-mail game: You both have a copy of the board, and you exchange moves. The Post Office doesn't know about the game.

Now, I'll admit this is growing in my mind as I think about it -- in fact, I may write an article based on this question -- but here's the idea, as some stories:

  1. You want to play a game of chess on line, so you go to a known URI to get one. You get back a page showing who, if anyone, is waiting to start a game.
  2. You pick one of the people waiting to play, and click the appropriate link. You get a new display (ajax magic in here if you want) with the board set up. One of you is white, white moves first.
  3. Whoever has the right to move enters a move, and commits (like taking your hand off the piece in a game.) The board updates and the right to move goes to the other player.

You don't need anything much in terms of server state --- although you might want to extend this by keeping track of moves etc, say for ranking -- and the question of who has the right to move can be computed entirely from the board page: if you have the right, you have a form for entering a move; when you send the form return back, the response returns a page to you with no slot for entering a move.

By "the token" I just mean some arbitrary representation of that one bit of state "My move"/"your move".

Seems as if the resources you need are

  • A "find a game" home page
  • A user page if you're tracking stats and such
  • a unique URI for every active game.
Charlie Martin
A: 

Thanks, Charlie. I'm still not clear how you get notified of the opponent's move in your scheme. Of course the question of who has the right to move can be computed simply--either from the board resource, or by using a separate resource that explicitly states whose turn it is to move. But how does a client know that this resource has changed? Does it have to simply continually poll, remembering the previous state, until it notices something has changed? In the Post Office model, the Post Office "pushes" a message to the client (your mailbox), which is not possible in HTTP.

I suppose this is part of a more general question: if there is a REST resource that I want to monitor for changes or modifications, what is the best way to do so? And is there something the server can do to make this easier for the client?

I think I'll actually post this as a separate question since I think it's interesting by itself.

Edited to add: http://stackoverflow.com/questions/405950/what-is-a-restful-way-of-monitoring-a-rest-resource-for-changes

Ross
A: 

One of the developers in planet.jabber is involved in Chesspark, an online chess community. They are using Jabber/XMPP extensively; if I'm not mistaken, these are his posts on the subject.

XMPP is an instant-messaging protocol, roughly based on small XML message exchange. There are libraries for most languages, including Javascript. I'm not sure it will fit your problem, though.

alex
A: 

I don't think REST is a good choice for such an application. The transformations and operations you need to do (make move, view move history, undo, get suggestion, turn notification) do not map neatly to REST's concept of resources. (The difficulties are perhaps more obvious if one considers how a RESTful API for more complicated turn-based games such as Scrabble or Monopoly might look.)

I think any sensible REST API would probably end up being a wrapper around something non-RESTful, such as a stateful protocol that sent portable game notation back and forth.

mjs