REST Resource Modeling

If I had to pick two top REST features, they would be resource modeling and resource representation. In this blog entry I explore the former with specific reference to a recent REST project I worked on.

Resource modeling refers to defining a resource name space and constructing the corresponding identifying URLs.

Some key issues in resource modeling are:

  • Define basic resources based on domain model – business objects become resources
  • Transform those non-CRUD business operations into resources and pick appropriate HTTP methods
  • Define URL namespace
    • Opaque URLs or not?
    • Express resource relationships as URL hierarchies or embed them in the representation?
  • Should we make user account explicit or implicit in the URL?
  • Other issues: matrix parameters, query parameters, queries

Basic Resources

Core business objects can be easily transformed into corresponding resources. Assume we have the following domain objects:

  • Video
  • Genre
  • Playlist – three concrete types: static playlist, dynamic playlist or playlist group
  • Player

The resource URLs could be:

  • /v1/ACCOUNT/videos
  • /v1/ACCOUNT/genres
  • /v1/ACCOUNT/playlists
  • /v1/ACCOUNT/players

There are typically five basic CRUD operations that we may want to perform on these resources:

  • Get all resources – GET /v1/ACCOUNT/videos
  • Get one resource – GET /v1/ACCOUNT/videos/1776
  • Modify one resource – PUT /v1/ACCOUNT/videos/1776
  • Add one resource – POST /v1/ACCOUNT/videos
  • Delete one resource – DELETE /v1/ACCOUNT/videos/1776

Note that Get all and the POST operations do not have a resource ID.

One seemingly minor but important note: you have to decide whether to use the singular or plural name for the resource – video or videos. Do not use both! I recently encountered a proposal for having /videos to return all videos and /video/1812 when you want to return one video. This makes little sense to me – there is one resource called video (or videos) not two resources – video and videos.

Non-Basic Resources

Unfortunately, not all business requirements can be mapped into the CRUD-like resource paradigm. What needs to be done is to noun-ify the “verb-like” business functionality by creating an “artificial” resource noun and then apply one of the verbs. Often it is not apparent if a POST or PUT is more appropriate.

The problem is how do we transform verbs into nouns? If we need to perform an operation on a resource that cannot fit into one of the four HTTP verbs, what to do? How do we come up with an intuitive resource name and then figure out which verb is most applicable. There are no real guidelines, and an inordinate amount of time can be spent on this exercise.

With SOAP you would simply create a new operation and be done with it. Obviously, the freedom to pick any operation name is a definite advantage of SOAP. I have seen meetings get bogged down in this morass. Typically the business analysts couldn’t care less how you implement their requirement while the architect has to worry about maintaining the semantic and logic coherence of the service.

An example that I faced in a recent project, where we received a new business requirement to recall and distribute videos. We already had our standard methods for a video, and the question was how to represent this in the best REST-ian fashion? Should we invent a new synthetic resources

  • /service/v1/videorecall
  • /service/v1/videodistribute

and then execute a POST. Somehow this “smells bad” – frankly there really is no concept such as video recall object. It seems that the noun-ify the verb pattern doesn’t fit the bill. Ultimately, the solution we opted for was POST with:

  • /service/v1/videos/recall
  • /service/v1/videos/distribute

Opaque URLs

Surprisingly even such an important topic such as the nature of a resource URL is not an agreed upon topic in the REST community. One school contends that human-understandable URLs are crucial, while the other side argues that clients should not assume any meaning to the internal structure of the URL. Suffice to say, that the understandable URL makes a more compelling case in my opinion.

Resource relationships

Resources have relationships to other resources. These relationships can be expressed in two basic ways:

  • Relationships specified in the URL as a hierarchical name compound
  • Relationships embedded in the output representation
    • Target resource as link
    • Target resource with details

An example best illustrates the issue. Our video resource has a many-to-many relationship with genres (categories).

In the URL approach, the following URL would retrieve the genres of a given video: /videos/1776/genres. The core resource /videos/1776 would retrieve only basic data for the video. If you wanted to obtain any relationships you would have to issue another call. To get permissions for a video: /videos/1776/permissions.

<genres>
<genre>
<id>11</id>
<name>Animals</name>
</genre>
<genre>
<id>22</id>
<name>Sports</name>
</genre>
</genres>

The embedded approach returns basic data for the video as well as relationship information. You still have to make a decision if you want link or detailed information on the references.

Relationships as links:

<video>
<id>1776</id>
<name>Touching the Void</name>
<genres>
<link href="http://www.k2.com/service/v1/acc/genres/11" />
<link href="http://www.k2.com/service/v1/acc/genres/22" />
</genres>

Relationships as details:

<video>
<id>1776</id>
<name>Touching the Void</name>
<genres>
<genre>
<id>11</id>
<name>Animals</name>
</genre>
<genre>
<id>22</id>
<name>Sports</name>
</genre>
</genres>
</video>

There are advantages and disadvantages with all approaches and ultimately the choice depends on your intended uses cases. The situation is also complicated by the PUT and POST methods. Typically you would want to use the same representation (data format) for GET and PUT/POST.

The URL Relationship patterns can lead to a chatty protocol since if your use case typically wants to grab all information related to a video, you would have to make 1+n calls where n is the number of video associations. It can be equally expensive to create or modify videos. Furthermore, if your object model requires mandatory relationships, the URL Relationship pattern cannot satisfy this requirement.

Google YouTube API uses the URL-based relationships. For example a video has an optional one-to-many association with comments. If there are comments for the video, the resource representation for a GET will contain a URL to a collection representing the comments.

<gd:comments>
<gd:feedLink href="http://gdata.youtube.com/feeds/api/videos/Vx4_OjyPqag/comments"   countHint="993"/>
</gd:comments>

Examples:

Make user explicit or implicit in the URL?

Most services have a concept of a current user (or account). The question then is, should we expose this user name in the URL or not?

  • /service/v1/USER/videos/1519
  • /service/v1/videos/1519

Both styles would require standard authentication. The case can be made that having the user name in the URL is redundant with authentication. On the other hand, if we want a richer URL hierarchy which would allow a user to access another user’s resources (with permissions, of course), then having the user name in the URL is important.


Resource Query Language

Any service will inevitably need some way to filter the amount of data returned. This is a complex topic, but it is worth to briefly examine some salient points. When designing a REST service, this can be a very important and time consuming task, so be prepared for significant effort.

Bare-bones REST offers us two basic ways to retrieve data:
Conceptually, we want to issue three kinds of GET requests:

  • Get all resources – /videos
  • Get one resources – /videos/1492
  • Get some resources – /videos?some_query_syntax

Bare-bones REST inherently supports the first two – the constraint-qualified GET presents us with a conundrum.

There is unfortunately no standard way to express a query and each vendor provides their own syntax. So when you are designing a REST service and you need querying (you will eventually need it), you will have to go through a non-trivial process to design a query language. This requires specifying the grammar, documenting it with examples, making it consistent across all resources, and writing lots of tests (hint: think combinatorial explosion of query options).

In my recent project we were fortunate to already have an in-house XPath dialect for our key domain objects. We were able to use (without modifications) this dialect for our internal domain service, internal and external SOAP services, as well as adapting it to the REST service with trivial effort. This was truly an example where proper foresight handsomely paid off. An example:

  • /videos?q=@id=’1776′
  • /videos?q=@name=’Aconcagua Adventures’
  • /videos?q=@id=’152′ or @id=’153′
  • /videos?q=@creationDate = xs:dateTime(‘2008-07-29T18:10:36.900Z’)

Some links on public web API query syntaxes:

Examples

Google:

ADO.NET Data Services:


Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s


%d bloggers like this: