views:

226

answers:

4

I'm working on an kind of an RPG game. And I'm trying to figure out a nice, clean and RESTful way to define inventory API.

inventory consists of several slots like head, chest etc (like in most RPG games).

Now I need to define REST API to move all items from slot X to slot Y.

few ideas I had:

  • well, obviously the inventory lives at /inventory
  • so 1st idea was to have smth like /inventory/movement and to have a CREATE on that to make it CRUD. so it will be POST /inventory/movement. this will be CRUD and REST, but it feels very bad.
  • another one was to have some magic attributes on the inventory and to just do update on it: PUT /inventory?move_from=A&move_to=B. This still doesn't feel too good.

so.. any idea for a clean CRUD REST solution for this?

UPDATE: just had another one: PUT /inventory/:to_slot?from=:from_slot - not sure still. why is the action on just one slot when 2 are involved? hmm... ugh!

+3  A: 

Since in REST you should always be acting on a resource, or on a collection of resources, in this case I would consider the 'MOVE' action as the REST resource. This may look incorrect at first, since we consider 'MOVE' to be a verb and not a noun, but this can make sense if the interface covers a high level of abstraction. In a high-level interface which exposes the options available to the user to control the game, you may want to act on the 'MOVE OPTION', which suddenly becomes a noun!

I would therefore use the POST verb to move an item within the inventory, since we would be issuing a request to create a new 'MOVE' action. Consider the following self-explanatory examples:

- POST /move/inventory/a/b
- POST /sell/inventory/a
- POST /use/inventory/b

The 'MOVE' command in raw CRUD operations is normally implemented with a CREATE followed by a DELETE. However, I think you would find it to be too low-level if you were to use raw CRUD operations on game resources like that.

If you were to GET an item from x and PUT it in y, where would you put the validation logic that checks if y is a valid destination? Should it be in the model (behind the interface) or within your game? If it should be in the model, then I think you should consider the high-level approach I described earlier. If, on the other hand you intend to handle this logic within the game (in front of the interface), then you can take the raw CRUD approach, as Jan suggested in another answer.

Note that if your RPG is going to be web-facing, it is imperative that you handle the game logic on the server side. In that case I would seek to map the REST interface one-to-one with the controls and options prompted to the user – and, again, I would suggest the high-level model proposed above.

Daniel Vassallo
+1  A: 

It should update a position_id of an ipotetic Item inside the domain logic, or something similar isn't it?

so I think you shuld PUT to the existing item:

PUT /items/:id?position_id=:position_id

sample:

PUT /items/1?position_id=2

you already know the "position from" because it should be already defined into your item model isn't it?

of course you can add the /inventory/ namespace if you like to make it more descriptive, so I suggest:

PUT /inventory/items/:id?position_id=:position_id

p.s. note that the parameters after the ? are not GET parameters :)

makevoid
not really, since there is no model for the 'instance of the item'. I do have Item model but it represents all instances of such an item. individual instances inside inventory are just hashes (using Cassandra)
Vitaly Kushner
+2  A: 

Vitaly,

do not think in terms of actions (move-to) but in terms of resources and state transfer. Here is how I would do what you ask with REST:

GET /game/inventories/5536

200 Ok
Content-Type: application/rpg.inventory+xml

<inventory>
  <slot href="/game/inventories/5536/slot">X</slot>
  ....
</inventory>





PUT /game/inventories/5536/slot

Content-Type: text/plain  (or what you need)

"Y"

GET /game/inventories/5536

200 Ok
Content-Type: application/rpg.inventory+xml

<inventory>
  <slot href="/game/inventories/5536/slot">Y</slot>
  ....
</inventory>

But there may be other ways, too.

Jan

Jan Algermissen
+1  A: 

Because the inventory is just a hash in a character model, you can get by with custom accessors for each of your important slots that modify the hash as required.

The RESTful move from slot A to B can be something like

 PUT /inventory with params:

 {inventory => {:worn_on_head => nil, :worn_on_left_arm => @item}}

You could potentially simplify the parameters with validations and call backs or even use the accessors themselves to to ensure that the same item isn't in multiple slots. Essentially shortening the parameters for a move request to something like:

 PUT /inventory with params:

 {:inventory => {:worn_on_left_arm => @item}} 

A safer bet is to just throw a validation error if a user tries to equip more copies of an item than they have, without replacing one of the other ones at the time of change.

EmFi
It uses Cassandra with a custom Ruby wrapper based on ActiveModel. it has many to many associations but in the case of invenory its just a full inventory hash inside character model.Im looking for the right way to present it from the outside w/o "leakinig" implementation details
Vitaly Kushner
I've never heard of Cassandra, but I've updated my solution to address this new information. The custom accessor method presented will hide the implementation details.
EmFi
Cassandra sure seems cool, here you can find something about it EmFi: http://incubator.apache.org/cassandra/ http://www.engineyard.com/blog/2009/cassandra-and-ruby-a-love-affair/
makevoid