REST - dealing with sub-resource access - rest

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

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.
REST in Practice
Restful Web Services

Related

RESTful API design - using a resource URI vs an ID

this is my first post, so please bear with me.
I am designing a new RESTful API and I have two design choices in how my clients interact with resources that they create.
As an example, I have a resource: "book", which is a simple, singleton resource.
Creating a new book is very simple:
POST https://api.mydomain.com/book
I know I can also use PUT if I want the operation to be idempotent.
This question is solely about the 200 OK response options, returning either:
an anonymous resource identifier (UUID) of the created "book":
{
book_id = 12345-67890
title = "a fantastic story"
}
a full FQDN URI to the created "book":
{
book_uri = "https://mylibrary.mydomain.com/upstairs/book/12345-67890
title = "a fantastic story"
}
This of course significantly effects the subsequent manipulation of the "book" by the client.
To get the title of the above book, the client API calls would be either:
GET https://api.mydomain.com/book/{book-id}
Example: GET https://api.mydomain.com/book/12345-67890
Notes: The client will always use the same endpoint as the POST call, with the book-id simply appended.
GET {book-uri}
Example: GET https://mylibrary.mydomain.com/upstairs/book/12345-67890
Notes: The client will use the {book-uri} object variable directly from the POST response. Importantly, the returned {book-uri) may be a completely different URI to that of the POST used to create the "book".
So my questions (please) are:
Q1) which is the better model for the client to use and why?
Q2) can you see any issues with using Option 2 in a high volume, commercial system?
Thanks for any help and answers in advance.
can you see any issues with using Option 2 in a high volume, commercial system?
So, Option 2, where the HTTP response includes a URI for the newly created resource, is how the web itself works, and the web seems to be doing pretty well as a high volume commercial system.
Note also that option #2 allows the server to control its URIs. For instance, if you later decide that you want to revise the resource model, and use different spellings for the resource identifiers, then you can do that without needing to make any changes to the client.
You can also introduce, for example, a URI shortening component, because again you've got an identifier with standardized rules for how it works.
You don't necessarily need to use a full URI - we've also got standardized rules for how a URI fragment can be used to compute a URI in a given context, so you'll likely have options like
{
book_uri = "/upstairs/book/12345-67890",
title = "a fantastic story"
}
... depending on whether or not the book resource is staged on the same host as the resource that handles the POST request.
Is this better? That's going to depend on what tradeoffs you need to make, and how much you value each of the benefits versus the costs.
The REST interface is designed to be efficient for large-grain hypermedia data transfer, optimizing for the common case of the Web, but resulting in an interface that is not optimal for other forms of architectural interaction. -- Fielding, 2000

Is it a good practice to use 'createModel' in REST?

I'm looking for a best way for implementing an endpoint of REST-full application that will be responsible for creating a new library orders. Let's assume that I have the following resources.
If I want to get all books of a particular author I can use the next endpoint:
HTTP GET
api/books/author/123
If I want to fetch all orders of a particular book I can use the endpoint provided below:
HTTP GET
api/books/456/orders
My question is what will be the most suitable URL and a request model for an endpoint that will create orders?
From my perspective it can be
HTTP POST
api/books/456/orders
And one more question. Is it a good practice in REST to use request models like CreateOrder? If I want to create a REST-full web application can I use the following request model:
class CreateOrder
{
AuthorId: number;
BookId: number;
ClientId: number;
}
Sometimes it makes me confused. Should request models look like our resources or not?
Let's assume that I have the following resources.
Your "resources" look suspiciously like "tables". Resources are closer to (logical) documents about information.
what will be the most suitable URL and a request model for an endpoint that will create orders
For the most part, it doesn't matter what URL you use to create orders. In a hypermedia application (think HTML), I'm going to submit a "form", and the meta data associated with that form are going to describe for the client how to compose a request from the form data.
So the human, or the code, that is manipulating the form doesn't need to know anything about the URL (when is the last time that you looked to see where Google was actually sending your search?)
As far as general purpose web components are concerned, the URL/URI is just an opaque identifier - they don't care what the spelling means.
A thing they do care about is whether the spelling is the same as something that they have cached. One of the consequences of a successful POST /x message is that the cached representation(s) of /x are invalidated.
So if you like, you can think about which cached document should be refreshed when an order is created, and send the request to the identifier for that document.
Should request models look like our resources or not?
It's not necessary. Again, think about the web -- what would the representation of create order look like if you were POSTing form data?
clientId=1&bookId=2
or maybe
bookId=2&copies=3
If the "who is creating an order" is answered using the authorization headers.
In our HTTP requests and responses, we are fundamentally sending message representations - sequences of bytes that conform to some schema. There's no particular reason that those sequences of bytes must, or must not, be the same as those we use elsewhere in the implementation.
Your end-point does not need to always start with /books. You can introduce another end-point /orders for creating or getting orders. So , to create an order , you can :
HTTP POST
api/orders
And does the 'request model' that you mean is the HTTP request body structure ? If yes, it does not need to be 100% match with your back-end persisted/domain model. Just include enough parameters that the server needs to know in order to create an order. (e.g. Include bookId rather than the whole book object etc.)
BTW , to get all books for a particular author , it is more common to use query parameter such as :
HTTP GET
api/books?authorId=123
What you are doing is not REST, it is CRUD over HTTP. REST does not care about your URI structures and resources are very far from database tables. If CRUD is all you need, then download a CRUD generator library https://github.com/search?q=crud+generator&type=Repositories, which will generate all the upper and you won't need to write it manually.

bulk GET using HATEOAS

I've seen many examples of HATEOAS where every resource has links to related resources. An API that returns N items of a certain resource per page, the client would probably need N calls to fetch any nested resource by consuming HATEOAS. For example:
GET city/documents:
[{
id: 1,
city: {
self: 'http://service.com/cities?filter=id==1'
},
document: { ... }
...
}, {
id: 2,
city: {
self: 'http://service.com/cities?filter=id==2'
},
document: { ... }
...
}]
FYI, the query parameter uses the FIQL syntax to define the filters.
Now, if the client was to fetch the city details for each document (to show on UI), it will probably need N additional calls. However in my case, the /cities API can additionally take multiple city ids like this: /cities?filter=id=in=(1,2) that can reduce N calls to one. Is there a way to articulate something like this using HATEOAS? I've read about the templates but not sure how should the template look like and how would client consume it?
I've seen many examples of HATEOAS where every resource has links to related resources. An API that returns N items of a certain resource per page, the client would probably need N calls to fetch any nested resource by consuming HATEOAS.
Yes. Less true in a world with Server-Push, where the server can proactively provide multiple resources in response to a query. If you imagine asking for a web page, and getting the html, and then also the images and the java script resources too, then you've got the right sort of idea.
API can additionally take multiple city ids like this: /cities?filter=id=in=(1,2) that can reduce N calls to one. Is there a way to articulate something like this using HATEOAS?
Yes.
Let's walk through it carefully. What you've done here is introduced a new resource, with identifier /cities?filter=id=in=(1,2). You might have another resource /cities?filter=id=in=(1,20) and another resource /cities?filter=id=in=(1,2000). In your implementation, these might be a "single endpoint" that extracts parameters from the identifier and uses them to generate the correct representation.
So what you get is something like a data transfer object - a large grained resource fetched in a single go.
I've read about the templates but not sure how should the template look like and how would client consume it?
The simplest example, which you have likely seen already, is a web form. You allow the client to provide the start and end elements, and the form processing takes that information and creates the specified URI from it.
/filtered-cities?start=1&end=2000
So the client needs to understand what the form is for, and how to identify the semantics of the different elements in the form. The agent needs to understand the processing rules that transfer the form data into the URI.
URI Templates are the same basic idea; they give you a domain agnostic language with which to describe where the parameters go in a resource identifier. The basic pattern is the same - there needs to be agreement about the semantics of the parameters, the server provides a URI, the client provides a parameter map, and the generic code can take care of the merge
uri = template.apply(parameterMap)
URI Templates aren't quite as powerful as forms; with a form, you can introduce a default value for a parameter, but there is no analogous capability in URI templates.
HAL-Forms may give you a better sense of how a form based approach might work in JSON.

REST design for update/add/delete item from a list of subresources

I would like to know which is the best practice when you are having a resource which contains a list of subresources. For example, you have the resource Author which has info like name, id, birthday and a List books. This list of books exists only in relation with the Author. So, you have the following scenario:
You want to add a new book to the book list
You want to update the name of a book from the list
You want to delete a book from the list
SOLUTION 1
I searched which is the correct design and I found multiple approaches. I want to know if there is a standard way of designing this. I think the design by the book says to have the following methods:
To add: POST /authors/{authorId}/book/
To update: PUT /authors/{authorId}/book/{bookId}
To delete: DELETE /authors/{authorId}/book/{bookId}
SOLUTION 2
My solution is to have only one PUT method which does all these 3 things because the list of books exists only inside object author and you are actually updating the author. Something like:
PUT /authors/{authorId}/updateBookList (and send the whole updated book list inside the author object)
I find multiple errors in my scenario. For example, sending more data from the client, having some logic on the client, more validation on the API and also relying that the client has the latest version of Book List.
My question is: is it anti-pattern to do this?
SITUATION 1. In my situation, my API is using another API, not a database. The used API has just one method of "updateBookList", so I am guessing it is easier to duplicate this behavior inside my API too. Is it also correct?
SITUATION 2. But, supposing my API would use a database would it be more suitable to use SOLUTION 1?
Also, if you could provide some articles, books where you can find similar information. I know this kind of design is not written in stone but some guidelines would help. (Example: from Book REST API Design Rulebook - Masse - O'Reilly)
Solution 2 sounds very much like old-style RPC where a method is invoked that performs some processing. This is like a REST antipattern as REST's focus is on resources and not on methods. The operations you can perform on a resource are given by the underlying protocol (HTTP in your case) and thus REST should adhere to the semantics of the underlying protocol (one of its few constraints).
In addition, REST doesn't care how you set up your URIs, hence there are no RESTful URLs actually. For an automated system a URI following a certain structure has just the same semantics as a randomly generated string acting as a URI. It's us humans who put sense into the string though an application should use the rel attribute which gives the URI some kind of logical name the application can use. An application who expects a certain logical composition of an URL is already tightly coupled to the API and hence violates the principles REST tries to solve, namely the decoupling of clients from server APIs.
If you want to update (sub)resources via PUT in a RESTful way, you have to follow the semantics of put which basically state that the received payload replaces the payload accessible at the given URI before the update.
The PUT method requests that the state of the target resource be
created or replaced with the state defined by the representation
enclosed in the request message payload.
...
The target resource in a POST request is intended to handle the
enclosed representation according to the resource's own semantics,
whereas the enclosed representation in a PUT request is defined as
replacing the state of the target resource. Hence, the intent of PUT
is idempotent and visible to intermediaries, even though the exact
effect is only known by the origin server.
In regards to partial updates RFC 7231 states that partial updates are possible by either using PATCH as suggested by #Alexandru or by issuing a PUT request directly at a sub-resource where the payload replaces the content of the sub-resource with the one in the payload. For the resource containing the sub-resouce this has an affect of a partial update.
Partial content updates are possible by
targeting a separately identified resource with state that overlaps a
portion of the larger resource, or by using a different method that
has been specifically defined for partial updates (for example, the
PATCH method defined in [RFC5789]).
In your case you could therefore send the updated book collection directly via a PUT operation to something like an .../author/{authorId}/books resource which replaces the old collection. As this might not scale well for authors that have written many publications PATCH is probably preferable. Note, however, that PATCH requires an atomic and transactional behavior. Either all actions succeed or none. If an error occurs in the middle of the actions you have to role back all already executed steps.
In regards to your request for further literature, SO isn't the right place to ask this as there is an own off-topic close/flag reason exactly for this.
I'd go with the first option and have separate methods instead of cramming all logic inside a generic PUT. Even if you're relying on an API instead of a database, that's just a 3rd party dependency that you should be able to switch at any point, without having to refactor too much of your code.
That being said, if you're going to allow the update of a large number of books at once, then PATCH might be your friend:
Looking at the RFC 6902 (which defines the Patch standard), from the client's perspective the API could be called like
PATCH /authors/{authorId}/book
[
{ "op": "add", "path": "/ids", "value": [ "24", "27", "35" ]},
{ "op": "remove", "path": "/ids", "value": [ "20", "30" ]}
]
Technically, solution 1 hands down.
REST API URLs consist of resources (and identifiers and filter attribute name/values). It should not contain actions (verbs). Using verbs encourages creation of stupid APIs.
E.g. I know a real-life-in-production API that wants you to
do POST on /getrecords to get all records
do POST on /putrecords to add a new record
Reasons to choose solution 2 would not be technical.
For requirement #2 (You want to update the name of a book from the list), it is possible to use JSON PATCH semantics, but use HTTP PATCH (https://tools.ietf.org/html/rfc5789) semantics to design the URL (not JSON PATCH semantics as suggested by Alexandru Marculescu).
I.e.
Do PATCH on /authors/{authorId}/book/{bookId}, where body contains only PK and changed attributes. Instead of:
To update: PUT on /authors/{authorId}/book/{bookId}
JSON PATCH semantics may of course be used to design the body of a PATCH request, but it just complicates things IMO.

Converting RPC style web service operation to a REST service

I'm converting a SOAP based RPC style "web service" to a JSON based REST web service using ASP.NET Web API.
Methods such as AddXYZ / UpdateXYZ / RemoveXYZ map cleanly to the HTTP verbs for POST/PUT/DELETE. Are there any best practices/guidance for mapping typical RPC style operations such as "ExecuteXYZ" or "AssignXYZ" style methods to it's REST counterpart?
My take is that such operations would map to corresponding URL addressable resources such as "ExecuteXYZRequest" and "AssignXYZRequest"
http://myhost/myservice/ExecuteXYZRequest
http://myhost/myservice/AssignXYZRequest
A request to execute "ExecuteXYZ" would then translate to a POST operation.
Getting the submitted request would translate to a GET(typically would be used to get the status of the submitted request).
http://myhost/myservice/ExecuteXYZRequest/1 <--- 1 is the ID of the request
Cancelling the request(assuming it's cancellable) would translate to a DELETE
POST would not really map to anything.
Does the above sound like a reasonable REST implementation or am I totally off in my thinking here?
Thought/guidance much appreciated.
UPDATE
Here is the specific example I'm trying to model:
A many to many relationship between a Contact and an Event entity. What would be the best way to model the membership of a Contact to an Event as a REST resource such that a Contact can be added/ removed from an Event. In the RPC land This would be a method such as "AssignContactToEvent" which takes the IDs of both entities and set up the relationship between these two. How can this be modeled naturally in REST as a resource. I recall that there is a concept of links and "rel" but cannot find a concrete practical example illustrating how to model something like this using Web API
Question is whether it makes sense for the RPC methods to map to REST
resources as indicated in the post
In a nutshell; no, it doesn't make sense to map methods to resources in the way you describe :)
In order to successfully "do REST" we have to think a little differently, and abandon all thoughts of RPC and CRUD-operations; these are really rather limiting once you embrace being RESTful!
The key abstraction of information in REST is a resource. Any
information that can be named can be a resource: a document or image,
a temporal service (e.g. "today's weather in Los Angeles"), a
collection of other resources, a non-virtual object (e.g. a person),
and so on. In other words, any concept that might be the target of an
author's hypertext reference must fit within the definition of a
resource. A resource is a conceptual mapping to a set of entities, not
the entity that corresponds to the mapping at any particular point in
time.
http://www.ics.uci.edu/~fielding/pubs/dissertation/rest_arch_style.htm
A method or action/verb is then not a resource, so it has no place in a URI -- unless of course you're building an application that allows people to create their own methods, which would be rather unusual!
Taking your specific example for a contacts and events relationship, it's important to understand that your 'AssignContactToEvent' is an action that happens under the Web-API layer and cannot be modelled RESTfully; I hope this will become clear in the course of the following examples :)
First we need some good resources to model a list of all Contacts, and a list of all Events:
/contacts
/events
These resources model an individual Contact or Event identified by an ID-token:
/contacts/{contact_id}
/events/{event_id}
The users of your application want to know who is involved in a particular Event, so we need a resource that models a list of the Event's participants:
/events/{event_id}/participants
When we want to add a Contact to an Event, we could POST a minimal Contact-representation (containing just the Contact-ID) to the Event's participants-list:
POST /events/{event_id}/participants/ HTTP/1.1
Content-Type: application/json
{'id': {contact_id}}
To remove a Contact from an Event:
DELETE /events/{event_id}/participants/{contact_id} HTTP/1.1
Your application-users also want to see at-a-glance the Events a Contact is participating in, so you need another to resource to model this:
/contacts/{contact_id}/events
Similarly, you can now GET a list of Events for the Contact, and assign Events using POST:
POST /contacts/{contact_id}/events/ HTTP/1.1
Content-Type: application/json
{'id': {event_id}}
The important point to take onboard is that whenever you need to model something new, you create a resource. The details of how you store the properties and relationships of data-objects are abstracted away behind a Web-API. Indeed, the data-storage technology might change in future, say from relational to object-store, or you change your programming language or framework, but in all cases your URI's (and Web-API) remain the same. REST and HTTP are designed to endure well-beyond the technologies that run under-the-hood.
As a final example of creating new resources, consider a resource that models a list of Contact's who have an organiser-role:
/events/{event_id}/organisers
or this one that models the list of Events that a Contact is organising:
/contacts/{contact_id}/events-organised
If you have a authentication-system, then you might want to see the events you are attending:
/my-account/events
I hope this helps to clarify the purpose of a Web-API and following RESTful principles.
There are two approaches that I have seen so far.
One is to map the action to a verb if there are very few actions so there is no collision. So if action is not safe nor idempotent then POST, otherwise if not safe but idempotent then PUT:
POST http://myhost/myservice/XYZ
Other is to define the action as a logical resource:
POST http://myhost/myservice/XYZ/Assignment
Later is richer and I favour that.
Few Important Points
RPC Endpoint -> REST Entry Point
RPC read method -> REST GET on Resource
RPC create method -> REST POST operation
PRC delete method -> REST DELETE operation
RPC SOAP Message -> REST PayLoad
additonaly , think about Cache headers , Content-Type headers like #Consumes, #Produces