Let's say I want to make a RESTful interface, and I want to work with foo
s based upon their IDs. Nothing new here:
GET /api/foo1
returns a representation (e.g. using JSON) of foo1
.DELETE /api/foo1
deletes foo1
.etc.
Now let me tell you that a "foo" is a collection type thing. So I want to be able to add a "bar" to a "foo":
PUT /api/foo1/bar3
adds bar3
to foo1
.GET /api/foo1/bar3
returns a representation of foo1
.DELETE /api/foo1/bar3
removes bar3
from foo1
.DELETE /api/foo1
deletes foo1
altogether.Now the question remains: what does GET /api/foo1
do? Does it it simply return a representation of foo1
as I originally assumed in this question? Or does it return a list of bars? Or does it return a representation of foo1
that is both a description of foo1
as well as includes a list of all contained bars?
Or should GET /api/foo1
merely return a representation of foo1
as I assumed at the beginning, and require a PROPFIND
request to list the bars inside foo1
(the approach taken by WebDAV)? But then in order to be consistent, wouldn't I have to change all my other list-type functionality to PROPFIND
, directly contradicting all those thousands of RESTful tutorials that say to use GET /api/foo1
to list the contents?
After some pondering, I think the best conceptual explanation from a RESTful perspective is that usually the "thing" is not the same thing as its "collection". So while in the WebDAV world a directory/
might be the same thing that holds its files, in the RESTful world I might have a separate directory/files/
subpath for the contained files. That way I can manipulate directories separately from the files that hold.
Consider a RESTful API for a farm which contains barns. The endpoint farm/api/barns/
might return a list of barns, one of which would be farm/api/barns/bigredbarn
. Naively I would think that retrieving farm/api/barns/bigredbarn/
would provide me a list of animals in the barn, which is what prompted this question.
But really the animals in the barn is only one aspect of the Big Red Barn. It might contain vehicles and hay:
farm/api/barns/bigredbarn/animals/
farm/api/barns/bigredbarn/vehicles/
farm/api/barns/bigredbarn/haybales/
With this approach the dilemma I faced does not arise.
The semantics of webdav has never really been reconciled with the idioms of RESTful interfaces.
In theory, GET should retrieve a representation of a state of a resource and PROPFIND should be used to retrieve the members of a collection.
So you should do this:
Most front end devs would freak out if you told them to use PROPFIND, although its completely supported in browser js implementations.
Personally i use a webdav/json gateway, where requests are made using RESTful idioms, but routed to my webdav implementation
For example i would do this:
GET /api/foo1/_PROPFIND?fields=name,fooProp1,fooProp2
And that would return
[
{ name : "bar1", fooProp1: "..", fooProp2 : ".."},
{ name : "bar2", fooProp1: "..", fooProp2 : ".."}
]
One advantage of this approach is that client's get to control the json properties returned. This is good because a rich API will have a lot of properties, but in most situations clients dont need all of them.
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