Reputation: 236
I'm evaluating a possible REST API design and would like to ask for feedback or best practices on ways of dealing with nested resources.
Consider the following (JSON expressed) data model of a contrived book library that is analogous to the data I'm looking at. Please ignore the fact that a book can exist without a library, etc.
{ "library-name" : "foobar",
"rows" :
[
{"row-id":"1",
"shelves":
[
{"shelf-id":"1",
"books":
[
{
"book":
{"book-name":"abc", "author":"someone"}
}
]
}
]
}
]
}
Suppose then that the possible REST API design is:
/library (the root API URI)
/library/{library-name}/
/library/{library-name}/{row-id}
/library/{library-name}/{row-id}/{shelf-id}
/library/{library-name}/{row-id}/{shelf-id}/{book-name}
For POST operations the server would implement functionality to allow:
There are some tradeoffs with the above:
Comments? What am I'm missing here (I have not found many examples of the above, which makes me think that it's not a common design pattern)?
Upvotes: 4
Views: 5187
Reputation: 1948
From your description, you meant to expose ‘row’ and ‘shelf’ as the integral part of the URL, which is fine if that is your design intent. That is where your question comes in since if ‘row’ & ‘shelf’ are the integral part of the resources’ URL, then your should not do ‘so-call’ bulk POST/PUT/DELETE operations but that is fine with GET as long as the book-name is unique.
A) -Create a book at specific location
HTTP POST /library/{lib-name}/{row-id}/{shelf-id}/{book-name}
Body: {json info for the book}
B) -Get all books
//in all library
HTTP GET /library/
//in a specific library
HTTP GET /library/{lib-name}/
//in a specific row
HTTP GET /library/{lib-name}/{row-id}/
//in a specific row & shelf
HTTP GET /library/{lib-name}/{row-id}/{shelf-id}/
C) -Get specific book
HTTP GET /library/{lib-name}/{row-id}/{shelf-id}/{book-name}
//If the book-name or ID is unique, you can access it from the toplevel
HTTP GET /library/books/{ book-name}
A) -Create a book
HTTP POST /library/{lib-name}/{book-name}
Body: {json info for the book including row & shelf}
B) -Get all books
//-in all library
HTTP GET /library/
//-in a specific library
HTTP GET /library/{lib-name}/
C) -Get specific book
//If the book-name or ID is unique, you can access it from the toplevel
HTTP GET /library/books/{ book-name}
The decision here is from the application point of view, is {row}/{shelf} critical to be exposed to the client in the URL as a way to manage the REST resources or they are merely attributes of a book.
If {row} & {shelf} are also REST resources for client to manage or are used to identify the unique path to the resources (book in this case), it makes sense to have them as part of the URL and they should be subject to constraints under REST/HATEOAS. In order words, you should not use the complex body to include all the 'sub-resources' in your POST.
GET is more subtle.
It is straightforward for GET on URL
/library/{lib-name}/{row-id}/{shelf-id}/{book-name}
GET can be applied on '/library/{lib-name}/'. In this case, the body should contain some form of structured links to the underneath resources like
[
{/library/{lib-name}/{row-id}/{shelf-id}/{book-name}},
{/library/{lib-name}/{row-id}/{shelf-id}/{book-name}},
...]
But if they are just attributes, then they could be part of the complex body since they are not adding any value from the view of either Addressability nor Links and Connectedness.
REST concerns about the following (copied from RESTful Web Services)
Two great books on REST and have some discussions on the topic that you are interested in.
Upvotes: 1