Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Best practices for returning representation of resource that is also a collection

Tags:

rest

get

webdav

Let's say I want to make a RESTful interface, and I want to work with foos 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?

like image 286
Garret Wilson Avatar asked Nov 06 '16 15:11

Garret Wilson


2 Answers

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.

like image 70
Garret Wilson Avatar answered Nov 03 '22 06:11

Garret Wilson


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:

  • GET /api/foo1/ - returns state of foo1 only
  • PROPFIND /api/foo1/ - returns the members of foo1

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.

like image 44
brad Avatar answered Nov 03 '22 05:11

brad