I am designing a REST API and I wonder what the recommended way to handle updates to resources would be. More specifically, I would allow updates through a PUT
on the resource, but what should I allow in the body of the PUT
request?
- Always the complete structure of the resource?
- Always the subpart (that changed) of the structure of the resource?
- A combination of both?
For example, take the resource http://example.org/api/v1/dogs/packs/p1
.
A GET
on this resource would give the following:
Request:
GET http://example.org/api/v1/dogs/packs/p1
Accept: application/xml
Response:
<pack>
<owner>David</owner>
<dogs>
<dog>
<name>Woofer</name>
<breed>Basset Hound</breed>
</dog>
<dog>
<name>Mr. Bones</name>
<breed>Basset Hound</breed>
</dog>
</dogs>
</pack>
Suppose I want to add a dog (Sniffers the Basset Hound) to the pack, would I support either:
Request:
PUT http://example.org/api/v1/dogs/packs/p1
<dog>
<name>Sniffers</name>
<breed>Basset Hound</breed>
</dog>
Response:
HTTP/1.1 200 OK
or
Request:
PUT http://example.org/api/v1/dogs/packs/p1
<pack>
<owner>David</owner>
<dogs>
<dog>
<name>Woofer</name>
<breed>Basset Hound</breed>
</dog>
<dog>
<name>Mr. Bones</name>
<breed>Basset Hound</breed>
</dog>
<dog>
<name>Sniffers</name>
<breed>Basset Hound</breed>
</dog>
</dogs>
</pack>
Response:
HTTP/1.1 200 OK
or both? If supporting updates through subsections of the structure is recommended, how would I handle deletes (such as when a dog dies)? Through query parameters?
Yes, always send the complete representation of the resource. Otherwise, you would (according to common definition and usage of PUT) replace the pack with just this one dog.
However, you might want to consider the following:
<dog id="1">
to the pack, too.Keep in mind that REST requires you to properly identify resources. packs are not really a subordinate resource to the dogs, and each dog should have some sort of unique identifier. Then, when accessing /packs/p1/1234, you would probably want to redirect to /dogs/1234. Or, alternatively, you would simply not make that URL available, despite accepting POSTing of subordinate resources to the respective pack.
The more I think about it, the more sense the POST approach makes. Maybe you could even have a /packs/p1/dogs/ resource for all the dogs, separate from the pack. Then, you can PUT stuff like owner information etc to /packs/p1, GET a list of all dogs via /packs/p1/dogs/ (which should contain a list of URLs to each dog in the pack, e.g. /packs/p1/dogs/1234, see HATEOAS), add a new dog to the pack by POSTing to /packs/p1/dogs/, and remove a dog by DELETEing /packs/p1/dogs/1235. Each dog could either be the full representation, maybe even with a redirect to /dogs/1234 etc, or a different representation of the dog in the context of this pack, but again with a link to the "full" dog. Depends on how you want to represent a single dog in a pack, and that will of course also influence what you actually POST to /packs/p1/dogs/. Full dog feels wrong, should really be just an ID as I showed above, maybe with additional data pertaining to the relationship with the pack.
PUT's effect is 'replace'. So, yes, you need to supply the complete representation with a PUT request.
If you want to do update only parts of the resource you have the following choices:
In your case, it would likely be best to make the dogs a sub resource (the collection of dogs of the pack) and POST to that in the usual POST-as-append manner