REST URIs with Semantics

The URIs for REST services should be opaque (they say...). It basically means client should not guess the proper URI string, but it should always get there step-by-step from the starting end-point.

For example, you start with http://example.com/first and you get the response:

{ "result": "ok",
"entities": [ 
  { "id": "book", "uri": "http://example.com/first/book" },
  { "id": "movie", "uri": "http://example.com/first/movie" }
]}

So, you know to continue exploration on books, you follow http://example.com/first/book without actually doing the string operation. That means the URI can be anything and it doesn't need to mention string "book", yet most URIs mention what they are good for. This has certain benefits:

  • when debugging, we can easily see what is URI intended for and it helps us orient better
  • it allows to build the system around URIs, so even new URIs are predictable (that does not mean you should create them with string operations, but at least when you see URI, you know it is malformed or not)
  • it is easier to talk about and share such URIs (we are not good in spelling 32-hex-digit long GUIDs)

Right now I'm puzzled a bit about that system of URIs, because one of the properties of the systems should be that they are somehow "complete". And in REST, we have actually matrix - URIs on one axe, and HTTP methods on another one. And when I build the matrix, I want to have it as complete as possible.

So, let's assume we have 3-segment URI, something like http://example.com/first/A/B/C and 4 basic HTTP methods: GET, POST, PUT and DELETE. Also, I have Entity framework behind my REST application ("entities" in terms of Domain Driven Design), with classes for entity itself (with methods like retrieve, update, and delete) and with classes for factory (to create new entities) and for repository (to search for entities). My matrix will look then following way:

REST URI GET POST PUT DELETE
/A class_A->query class_A->create( post_data ) ?? ??
/A/B class_A->retrieve( id_B ) ?? class_A->update( id_B ) class_A->delete( id_B )
/A/B/C class_C->query( parent = class_A/id_B) class_C->create( parent = class_A/id_B, post_data) ?? ??
/A/B/C class_A->retrieve( id_B, part = part_C) ?? class_A->update( id_B, part = part_C ) class_A->delete( id_B, part = part_C )

I know this is not perfect object-oriented design (the class here is more like dispatcher, or facade), but it is not point here. The point here is how to fill the cells with ??.

There are two patterns:

  • instance operations - if id_B represents the ID of the entity class_A, you can use /A/B to access the instance and you can retrieve, update or delete it, or you can use complete /A/B/C to perform "partial updates" of entity, when part_C is used to describe the part
  • factory/repository operations - they are "static methods", either on plain /A with no ID (class_A represents class or entity here), or with complete triplet /A/B/C where class_C represents "second level class", operated within its parent entity class_A with ID id_B

Now, for this to be true "system", it requires to fill cells with "??" with something interesting and reasonable and consistent.

What could it be?