Sunday, May 23, 2010

Relationship management in RESTful web services - Part II

In the Part I on this topic, I described an approach that makes relationship between two resources a first-class resource. In this post, I would describe the second approach I had mentioned in Part I, the relationship as a sub-resource.

Relationship as a sub-resource
Here, the relationship is managed as a sub resource of the resource that acts as object in the relationship. Let's take an example.

Roles ROLE_COLLECTIONMANAGER (id: 814ed9d4-3315-44fc-993b) has permission (id: e62d2306-518b-414b-9591) to access a resource named intakes

Permission as object in relationship

If the object of the relationship is a permission and subject being role, i.e. a permission to access resource named intakes is given to role ROLE_COLLECTIONMANAGER, it could be created using the following API. We assume here that both the permission and role are already created using respective POST operations and we are only trying to relate these over here.

Here, e62d2306-518b-414b-9591 is the id of the permission. The sub-resource is permroles that indicates the context of the relationship, i.e. the relationship is between permission and role and not permission and user for example.

As you might notice, we have added some additional data about the permission (resourceName) as well as the role (roleName). This is optional and for convenience purposes only. Also, it would be possible to associate one or more roles with the same permission in a single POST request. So, associating both ROLE_COLLECTIONMANAGER and ROLE_CURATOR (id: 3772624d-1ab3-4e47-a26d-191fc6437410) with the same permission would look like the following.

Role as object in the relationship

The same data structure could also be used with role as an object in the relationship. That is, ROLE_COLLECTIONMANAGER has permission(s) to access intakes (and collectionobjects) resource. This could be accomplished using the following API. Note that id 814ed9d4-3315-44fc-993b represents ROLE_COLLECTIONMANAGER.

Here, POST does return an id to comply with RESTful architecture, however, because relationship is not treated as a first-class resource, this id is meaningless for subsequent operations such as GET and DELETE. Let's assume that we received id 123 for now. Also, more subjects could be associated with the same object using the POST operation again as follows. That means, POST also acts as PUT.

The GET operation would use the id of the object (permission:e62d2306-518b-414b-9591 or role:814ed9d4-3315-44fc-993b) in the relationship to access the relationships with all the subject(s). The GET operation would return the same data as was posted but with a union of all subject(s).

Note the last element of the URI, 123, it is just a filler for an id as the relationship is not a first-class RESTful resource.

All 3 roles associated with a permission are returned.

According to the RESTful architecture, the DELETE should only take an id of the resource to be deleted. The following operation would delete relationships between the given object and all its subjects.

This is good and bad. It is good from efficiency purposes in the sense that all the relationships between subjects and given object could be deleted in one shot. However, it is bad that individual relationships between a subject and given object cannot be deleted as there is no way to uniquely identify such a relationship.

Overall, I like the sub-resource based approach as it is more convenient to navigate to relationship(s) from an object in the relationship. Also, it supports bulk operations, i.e. associating more than one subjects with an object with a single request is possible and GET returns relationship between an object and all the subjects that object is related to in the context of that relationship.

However, this is a bit un-RESTful approach as the identifier returned from POST is meaningless for the GET and DELETE operations. Also, DELETE is not fine-grained, i.e. deleting a relationship between an object and a subject is not possible. It would be better if there was a way to make that possible (see an alternative). The approach described in Part I does not have this problem. Perhaps a hybrid is possible? Would a hybrid approach more complex? I am eager to hear your viewpoints. Feel free to send me comments if you have taken an approach which does not suffer from the limitations I have described.

Reblog this post [with Zemanta]

No comments:

Post a Comment