Domanda

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:

  • Adding a new book, by performing a POST directly to /library/{library-name} encoding all the details of the book to a shelf, row, etc inside the nested data structure (like shown).
  • GET operations would be allowed at each recourse level. The GET would return the fully nested data (eg returning as JSON data all the rows/shelves and books for a given library, etc).

There are some tradeoffs with the above:

  • A given book resource can be accessed by several URIs. eg A POST to /library/{library-name} could be creating a book, as could a POST to /library/{library-name}/{row-id}/{shelf-id}. In such indirect POST cases, the data rather than the URI identifies the actual target sub-resource. Is this RESTfuL?
  • Allowing resources to be handled via their parent resource in POST/PUT operations is useful in bulk operations; saves on number of round trips. This benefit comes at the cost of a more elaborate data structure and handler code that the client and server have to deal with.

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)?

È stato utile?

Soluzione

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.

I can see you have the follow business operations

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}

If row & shelf are not important part of the URL, you will have

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}

Updated

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)

  • Addressability
  • Statelessness
  • Representations
  • Links and Connectedness
  • The Uniform Interface

Two great books on REST and have some discussions on the topic that you are interested in.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top