onsdag, april 18, 2012

RESTful resources are not typed

I have always been puzzled by this quote from Roy Fielding [1]:

    A REST API should never have “typed” resources that are significant to the client

How on earth is a client supposed to be able to do anything with a resource if it is not allowed to know the type of it?

The context here is a REST API that exposes business data from a certain business domain. This could be e-procurement, biochemistry or what ever else you could think of. But lets go with the e-procurement example and imagine a web shop that exposes catalogues, sales orders, customers and so on.

A machine-driven client may be interacting with this API in order to automatically buy something, lookup customers, gather sales statistics and what not. The point is - at a given time the client has a specific task to solve. Lets go with an example like this; "Get information about a certain sales order and print a letter to its customer".

Now, how can the client get the address of the customer unless it knows it is, well, of type "Customer" - and thus having a well known set of properties like "Name", "Birthdate", "Customer number", "Billing address" and so on?

Down the rabbit hole we go ...

Typed resources is a misconception

It is extremely easy to fall into the trap of thinking of resources as having specific types. A hyper link with the link relation type "customer" would surely point to a "Person" or perhaps a more generic "Contact" resource - right? Just like the resource identified by http://example.com/people/Pete must certainly be a "Person" too - right?

But what if the "customer" hyper link referred to http://www.cph.dk, or if you were presented with the URL http://example.com/fgx27-yw - what could you then conclude about types? Nothing. At the URL www.cph.dk we find a homepage from Copenhagen airport - that is not something which has a business domain type in traditional understanding - and fgx27-yw should be meaningless to anyone.

From a client's point of view, there is no such thing as a typed resource.

Resource views? No. Facets? No. Capabilities? No. Ah, yes, Media types!

Instead of talking about "types" we can reframe our thinking and talk about various views or facets of a resource - or perhaps the capabilities it offers to a client interacting with it. Just make sure you quit thinking of what the resource "is" and think of what it can do for you instead.

Example; a client that has been given the task of printing a letter to the customer at some {Customer} URL can ask the resource at that URL to return a VCard such that the client can get a mailing address - and it couldn't care less if the resource was a cat, city, or movie actor, as long as it it was able to return a VCard when asked for it.

Such a view of a resource is called a representation and the representation's format is the media type and asking for a specific media type is called content negotiation.

Media types

Lets take a look at some other media types and see how they can be applied without knowing the type of a given resource.
  1. A client following a link relation "news" may ask for application/atom+xml for a news feed.
  2. A client following a link "destination" might ask for application/gml+xml to get a geographical model of the destination.
  3. A client following a link "contact" might ask for text/vcard to get in contact with, well, the contact. It could also ask for application/vcard+xml in addition if it supported both formats. The server would then return one of them, depending on what it supported.
Again, there is absolutely no mentioning of the type of the resource. As an experiment, try to imagine the resource at www.cph.dk as the target of the above links ... works quite well, right? All the client need is an understanding of how the next resource in the application flow is related to the current one - it does not need to know what that resource is as long as it can ask for a representation that solves the given task of the client.

Domain specific media types

Now back to the original task of getting business domain specific details from a resource - without knowing the type of it. How can we get Name, Birthdate, Order No. and so on from the resource? What is needed is a domain specific media type - a media type which is specialized to a specific business domain.

Example: suppose a client needs the details of a sales order for a specific customer. All it needs to do is
  1. follow a link to the resource that someone else says is the sales order for the customer, and 
  2. ask for a media type that covers the sales order details needed.

This of course assumes that someone has defined a suitable domain specific media type that can be used this scenario. If no such thing exists then go ahead and design your own. Just make sure you register it!

Media type standardization

A media type must be registered with some authority - otherwise there is nothing for the client and server to agree on when communicating. On the big world wide web this is the job of IANA [2]. But it might as well be some central authority inside a big enterprise corporation - as long as (all) the client(s) and the server can agree on it.

Some business domains can be rather difficult to standardize and in these cases IANA may not be the place to go. Luckily there is nothing inherently wrong about creating private media types - as long as they stay inside the enterprise.

More capabilities

A media type is not restricted to only define the "wire format" or "serialization format" of a resource. It also defines link relations like "customer", "orders" or "owner" as well as how to interact with the resource. The typical interaction is navigation by following a URL - but media types can also define how to write data back and update resources aka "forms" handling. In this way media types goes way beyond simple understanding of the type of a resource.

Media type design is a whole art in itself that Mike Amundsen has written quite a lot about [3].

Links

[1] REST APIs must be hypertext-driven - http://roy.gbiv.com/untangled/2008/rest-apis-must-be-hypertext-driven

[2] MIME Media Types - http://www.iana.org/assignments/media-types/index.html

[3] Hypermedia affordances - http://amundsen.com/blog/archives/1109


4 kommentarer:

  1. Why must private media types stay inside the enterprise? Private media types also can be specializations of public media types. The public media types (eg application/xml) provide the default behavior through generic clients. The specializations (application/xml;type=destination), understood by the enterprise clients, provide specific behavior for the enterprise. The web can scale to accommodate enterprise applications!

    SvarSlet
  2. First of all I haven't been able to find a "type" parameter for application/xml in RFC 3023, so its not legal unless that RFC is superseded by another one.

    But lets assume it is allowed ... then it *must* be supported by server frameworks as part of the content negotiation. Conneg is the core of being able to abstract away the thinking of resources as having a specific type. Try take a look at http://www.ietf.org/rfc/rfc3023.txt appendix A.6 and forth - it has some good reasons for not using a type parameter or similar.

    Besides that you could also use a Link header with the "profile" relationship. Mark Nottingham has a piece on this at http://www.mnot.net/blog/2012/04/17/profiles - but be sure to read James Snell's comment on http://chmod777self.blogspot.com/2012/04/on-profile-link-relation.html.

    SvarSlet
  3. But you could in fact do it in application/xhtml+xml which has a "profile" parameter. HTML may not be the most intuitive format for API data, but it is doable as some sort of micro format.

    It does still require frameworks to support content negotiation with parameters. Don't know if that is normal or not.

    SvarSlet
  4. Seems like HTTP includes parameters in content negotiation, see http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.1, so "Accept: application/xhtml+xml; profile=xyz" should be doable.

    SvarSlet