I am developing an online game where characters can perform complex actions against other objects and characters. I am building a REST API, and having a lot of trouble trying to follow even some of the most basic standards. I know that REST isn't always the answer, but for a variety of reasons it makes sense for me to use REST since the rest of the API uses it appropriately.
Here are some tricky examples:
GET /characters/bob/items This returns an array of items that Bob is carrying.
I need to perform a variety of 'operations' against these items, and im having a very difficult time modeling this as 'resources'.
Here are some potential operations, depending on the nature of the item: throw, eat, drop, hold
This is complicated because these 'operations' are only suitable for certain items. For example, you can't eat a sword. Moreover, 'eat' essentially has a side-effect of 'deleting' the resource. Using 'throw' may also 'delete' the resource. Using 'drop' may 'transform' the resource into another resource type. 'Throw' requires that I provide a 'location'. 'Hold' requires that I supply which hand to hold the item in. So how do you model these operations as resources? None of them are 'alike' because they each require different parameters and result in completely different behaviors.
Currently, I have an 'actions' resource that I POST these arbitrary actions to. But this feels way too RPC and non-standardized/discoverable:
POST /actions/throw { characterId: 5, itemId: 10, x: 100, y: 150 }
I try to stick to resources and GET/POST/PUT/PATCH/DELETE where possible, but the base verbs tend to map directly to CRUD calls. Other, more complex operations generally can't be mapped without additional information.
Focusing on the resources, I'd probably do something like this (posting messages to the resources):
POST /characters/bob/items/{bombId}?action=throw
POST /characters/bob/items/{foodId}?action=eat
POST /characters/bob/items/{potionId}?action=add&addedItem={ingredientId}
Return an error when the action is not appropriate for the item.
Where I want a resource to “do a complex action” while remaining RESTful, I'd POST a complex document to the resource that describes what I want to happen. (The complex document could be in XML, JSON, or any number of other formats.) This is somewhat distinct from the more common pattern of mapping POST to “create a child resource”, but the meaning of POST is “do non-idempotent action defined by body content”. That's a reasonable fit for what you're after.
As part of the HATEOAS principle of discovery, when you GET the resource which you will later POST to, part of the document returned should say what these complex action documents are and where they should be sent to. Logically, think of filling in a form and submitting it (even if the “form” is actually slots in a JSON document or something like that).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With