Sound advice - blog

Tales from the homeworld

My current feeds

Sat, 2006-Jun-17

REST XML Protocols

I would like to offer more than a "me too" in response to Kimbro Staken's 10 things to change In your thinking when building REST XML Protocols. The thrust of the article includes some useful points, but is not quite the set I would put forward. I'll crib from his list, expand, and rework.

  1. You are using REST and XML for forward and backward compatability of communications. Don't think in terms of Object-Oritentation or Relationional DatataBase Management Systems. These technologies are built around consistent modelling within a particular program or schema. REST and XML are there to give you loose coupling that will keep working even as cogs are pulled out of the overall machine and replaced. The interface between your applications is not an abstract model which can be serialised to xml. The interface is the XML and URI space. Abstract models need to be decoupled from the protocol on the wire. They can change and differ between different processes in the architecture, and they do.
  2. Schemas are not evil, but validation of input based on the schemas of today may be. From the perspective of compatability it is important not to validate input from other systems in the way current schema languages permit. Instead, consider a schema that defines how to parse or process your XML. You can generate your parser from this little schema language so your "hard" code only needs to deal with the fully-parsed view of the input.

    Define a schema which says which xml elements and attributes you expect. Define default values for this data wherever possible. Only declare elements as mandatory when your processing can literally not proceed without it. Don't expect your schema to match the schemas of other programs or other processing. They will have different priorities as to what is essential and which defaults they can safely assume.

    Validation of your own program's output is a worthwhile process, but don't expect to be able to use the same schema as is used on the other side of the connection. Your schema should describe what you expect to output. It should be used as part of your testing to pick up typos and other erroneous data output. You should expect the receiver of your data to process it based on whatever part it understands. Speaking gibberish may cause the remote to silently do much less than you expect.

  3. Consider backwards-compatability as soon as you begin developing your XML language. Borrow terminology and syntax heavily from existing formats so that your lexicon is as widely-understood as possible. Do this even to the point of embracing and extending. It is better to introduce a small number of terms to an existing vocabulary and namespace than it is to define your own format. Be sure to push your extensions upstream.

    XML is a dangerous technology for REST thinking. The use of XML is sometimes seen as part of the definition of REST. REST is actually more at home with html, png, mp3 and other standard formats. REST requires the XML format to be understood by everyone. You are actually only approximating REST if your XML format isn't understood by every relevant computer program in the world. Consider not inventing any new XML language at all.

    New software should still be able to process requests from old software: Once you have version "1.0", you are never permitted to remove structures or terminology.

    Old software should be able to process requests from new software: Once you have version "1.0", you are never permitted to add structures you depend on being understood.

    Corollary: Never encode a language version number into your XML file format. If someone has to key off the version number to decide how to parse an XML instance document, it is no longer the same XML language. Give it another name instead, or live with the limitations of the existing format.

  4. Always think of your XML instance document as the state of an resource (i.e. an object) somewhere. GET its state from the server. PUT a new value for its state back to the server. On the server side: Define as many resources as you need to allow for needed atomic state updates. These resources can overlap, so there may be one for "sequence of commands, including whether or not they are configured to skip" and another one for "whether or not command one is configured to be skipped". Use POST to create new objects with the state clients provide.
  5. Use hyperlinks to refine down from the whole state of an object to a small part of that state. Use hyperlinks to move from one object to another. Never show a client the whole map of your URI path and query structure. That leads to coupling. You can have such a map on the server side, but clients should be focused on viewing one resource at a time. Give them a resource big enough so that works.

    Letting clients know ahead of time the set of paths they can navigate through increases coupling, especially if that information is available at compile-time. Don't fall into the trap on the client side of saying "This as a resource of type sequence of commands, so I can just add `/command1` to the end of the path and I'll be looking at the resource for the first one. Servers can and do change their minds about how this stuff is organised.

  6. Use URIs for every identifier you care about. Make sure they are usefully dereferenceable as URLs. Even if you think that an id is local to your application, one day you'll want to break up your app and put the objects and resources that form parts of your app under different authorities.
  7. Use common representations for all simple types. Don't get funky with dates and times. Don't use seconds or days since an epoch. Use xsd as your guide to how things should be repsented within elements and within attributes.