Web Resource Description Language ("Word-dul")

(replaces Web Service Operations Language and Simple Web Service Behaviour Language)

Status: Rough -- expect mistakes and typos...release early and often!

Preliminary WRDL DTD

WRDL example 1: Meerkat service

WRDL example 2: Babelfish

Preliminary WRDL implementation for Python

Jason Diamond is working on a WRDL implementation for C#.

Abstract

REST is defined by four interface constraints: identification of resources; manipulation of resources through representations; self-descriptive messages; and, hypermedia as the engine of application state.

The basic model of a REST Web Service is that services are described as webs of linked resources. Typically the resources will be represented by dynamically generated XML documents but that is not necessarily the case. Just as with services based on COM, CORBA or SOAP, it is useful to have a declaration of a resource's operation in advance so that reliable software can be constructed with less testing. At the very least, static declarations are a very useful communication tool.

Insofar as a service consists of XML documents, XML schemas provide a partial description of the service. What they do not describe is the transitions from one document to another: the service's runtime behaviour. That's what WRDL does. It is intended to be the IDL/WSDL for HTTP web services. Just as with IDL it may one day make sense to "bind" WRDL into a statically typed programming language to make the construction of type-incorrect client software impossible.

Model

Think of a web service as a web of resources. The resources are represented by XML document types. The "find airline seat" document points to the "reserve seat" document through a URI. That document points to the "purchase ticket" document through a URI and so forth. Once you start any business process the rest of the documents are generated specifically for you with a new URI keeping track of your state. Each document has associated with it an XML Schema. But the resource behind the document has associated with it an operational description.

You use the service at runtime by pointing a program at a resource URI and the resource description URI, just as you might point an XML schema checker at an XML document and an XML Schema. If you ask to GET or PUT a representation, the WRDL checks that the XML representation retrieved or sent is one of the legal representations for this service. If you ask to POST a representation, it checks that the resource you send is a valid subordinate (child) resource type of the resource. Constraints may also be placed on headers and query parameters. Undeclared methods are unavailable.

When a document is returned as a response to a request, the WRDL engine annotates every hyperlink in that document with a resource type, based on configuration data that is associated with the XML document type. This information could be presented to the program as extra attributes on the DOM or as static type declarations in a "compile-time binding". Based on the resource type, the system knows what are the legal operations and the legal inputs and outputs for the operations.

Resource types declarations

An element of type resourceType declares a resource type. A resource type has a name attribute which holds a "QName". A resource type has a list of valid representations as an attribute of type "List of QNames". A resource type also has one or more methods.

<resourceType name="purchaseOrder" 
        representations="ebxmlpo cblpo">
    <method name="GET">...</method>
    <method name="POST">...</method>
    <method name="DELETE">...</method>
</resourceType>

Method declarations

Method declarations are used to describe the methods that may be applied to resources of a particular type. For instance a mailbox resource type might support a PUT and GET of a MBOX representation, POST of a MIME message and DELETE (which removes the mailbox).

method element

A method declaration is an element of type "GET", "POST", "PUT", "DELETE" or "otherMethod". otherMethod has a "name" attribute which represents the method name. Methods have "input" and "output" sub-elements.

creates attribute

POST methods and otherMethods have a "creates" attribute. It declares the resourceType of the sub-resource that will be created (if any). If it is absent it means that no sub-resource will be created (and no Location: header should be returned).

input element

The "input" element has an optional "representations" attribute that lists the valid representations that may be submitted. The default input representations list for GET and PUT methods are inherited from the parent resourceType element. The default representations list for DELETE methods is empty.

output element

The "output" element has a "representations" attribute but this is usually defaulted. The default output "representations" list for a PUT or DELETE is empty and for a GET is inherited from the "resourceType".

If an input or output element requires no child elements or attributes then that element it may be just omitted.

query and header elements

The "input" and "output" elements also has "query" and "header" sub-elements. "query" and "header" elements have "name", "type", "default" and "use" attributes just as for declaring attributes in XML Schema. Extra headers are always allowed, however. This is key for extensibility. There may one day be a feature to allow for "extra" query parameters, also for extensibility.

<resourceType name="purchaseOrder" 
        representations="ebxmlpo cblpo">
    <method name="GET">
      <input>
        <query name="itemtypes" type="integer"/>
        <header name="pragma" value="no-cache"/>
      </input>
    </method>
    <method name="POST" creates="ebxmlPoResource">...
      <input representations="">
        <query name="name"/>
        <query name="items" type="integer"/>
      </input>
      <created representations="cblpo"/>
    </method>
    <method ...>...</method>
</resourceType>

<resourceType name="digitalSignature"
       representations="some-dsig-standard">
    <method name="PUT"/>
</resourceType>

Representation type declarations

An element of type "representationType" declares a representation type. It has an optional "mediaType" attribute. If it is provided it must be a MIME media that matches the content-type delivered with the representation or inferred from other clues (if any). For simple apps, consider using types from MIME-RPC.

representationType may also have an attribute named "namespace" which represents the namespace that best represents the appropriate processing for the document.

A particular document could match multiple representation types. This is not a problem because representations are only checked in a boolean fashion: "Does the input or output document match one of these representation types?" The client application presumably knows which one it requested (using content negotiation or some other means).

Schema elements

Representation types may have one or more "schema" sub-elements. Each should have either a "mediaType" attribute or a "namespace" attribute. A future version of this specification will have examples of appropriate declarations for schemas of type DTD, W3C XML Schema, RELAX and RDF.

Reference elements

Representation types may have zero or more "reference" sub-elements. Each one of them describes how to bind a resource type to a particular attribute value or element content. In other words it extends the XML Schema concept of anyURI with strong type checking. Each may have the following attributes:

"match" (required)
selects the appropriate attributes or elements to associate with this reference type. This is just as in the XSLT key feature.
"name" (required)
A document-unique name, used for data binding (see below).
"key" (optional)
An XPath specifying some string property of the element to be used as a key for lookups in a programming language. For instance if a document type had the structure <foo name="blah">http://www...</foo> then the key might be "name" so that URIs could be addressed by name. This is just as in the "use" attribute of the XSLT key feature.
"type" (optional)
The resource type to use to annotate them.
"occurs"
must take the value "single" if a single occurence is expected and "multiple" if multiple occurrences are expectred.
<representationType name="xslt" mediaType="text/xsl">
        
    <reference name="includes" 
                  match="xsl:include/@href"
                  type="xsltResource"/> 
    <reference   name="imports" 
                    match="xsl:import/@href"
                    type="xsltResource"/>
</representationType>

<representationType name="po" mediaType="text/ebxmlpo+xml">
        
    <reference name="approve" match="approve_po" type="digitalSignatureResource"/>
    <reference name="cancel" match="cancel_po" type="digitalSignatureResource"/>
</representationType>

In the future it may be possible to hoist this information right into the XML Schema so that a service and a schema may be defined together and in particular every URI attribute can be strongly-typed right where it is defined rather than through an XPath lookup.

In the future, it will be possible to split apart MIME/multipart objects. Also, some kind of include feature is necessary.

Rough API

Here is how I envision using this in a statically typed programming language. First a binding generator reads in all of the schemas and resource descriptions. It makes classes that represents the XML document types, just as today's binding technologies do. But it also makes classes that represent the resources behind the XML representations. This allows you to navigate from resource to resource as objects with strong, static typing. For each resource you can call one or more HTTP methods. The code is statically type checked and then all documents sent back and forth are checked again at runtime.

The return value of an HTTP method invocation is an object with the following properties: "body" -- a string or DOM document depending on the media type, "headers" (a hashtable), "resource" (if a new resource was created), "status".

Resources have pointers to other resources in a "references" property. This property has sub-properties that are named after references in the WRDL.

Note that these examples are not yet aligned with the ones above. I just want to show some of the more interesting bits of the proposed API. Better tutorial materials are a priority.

# here's my starting point
String uri = "http://www.somecompany/purchaseorders"

# here's where I bind to the compiled version of my WRDL
PurchaseOrdersResource pos = new PurchaseOrdersResource(uri)

# no network traffic yet...

# now I create a new XML document input
# in reality I would probably use data binding to do this instead of
# the DOM but I don't want to confuse things
DOMDocument po = new DOMDocument(...)
po.addChild(...)
po.addChild(...)
...

# now I POST it and thanks to the WRDL "creates" attribute, I know
# that the output resource will be a PurchaseOrderResource 
# POST methods return an object with a .resource attribute if they
# create new resources
PurchaseOrderResource por = pos.POST(po).resource

# now I can apply any HTTP method -- method name includes
# representation type
DOMDocument po = por.GET_cbl_PO().body
print po.documentElement.tagName

String contenttype = por.HEAD().headers["content-type"] 
                          # no, this isn't spec'ed properly yet

# let's presume the purchase order resources point to customer
# resources and I want that information. I get that from the
# "references" property. 
CustomerResource cust = por.references.customer("32343")
# 32343 is the key...it looks up a reference of type "customer" with
# an appropriate key value.

# Do a GET with an appropriate representationType to get it.
DOMDocument cust = por.GET_biztalk_customer_record()

# I've had my fun. Delete it...we're just testing after all!
por.DELETE()

#methods can be chained. (need to think about this more!)
someresource1.POST(someresource2.GET())
someresource1.PUT(someresource2.GET())

#if we add a WATCH method to HTTP
someresource1.WATCH(someresource2)

Note that the "references" object is attached to the resource even though the actual URIs come from representations. (what about name clashes between URIs in different representations...it's almost like the names should move up to the resource but the problem is that the XPaths have to stay with the representations. I could introduce an object that binds representations to resources, potentially renaming references but that's another object...)

Python WRDL example

def main(url):
    wrdl = Wrdl("meerkat.wrdl")

    # bind a resource type to a URI
    r = wrdl.newResource("meerkat", 
             "http://www.oreillynet.com/meerkat/")

    # now GET that resource...any representation
    res = r.GET_meerkat_xml_flavour( channel=555,
                    timePeriod="7DAY", search="Prescod") 

    # alternately, GET a particular representation
    # (in this case "meerkat_xml_flavour")
    res = r.GET_meerkat_xml_flavour( channel=555,
                    timePeriod="7DAY", search="Prescod") 

    text = res.body() # get resource body 
    assert text.find("Prescod")>0 # vanity assertion

    # get a list of references (XML or HTML hyperlinks)
    links = res.references("link")
    assert len(links)>1 # sanity check

    # download representation of first link
    newres = links[0].GET() 

    # get the resource body for that link
    text = newres.body()
    assert text.find("Prescod")>0 #vanity assertion

    wrdl = Wrdl("babelfish.wrdl")
    s = wrdl.newResource("babelfish", 
            "http://babelfish.altavista.com/tr")

    # do a POST
    res = s.POST(text="Hello world", languages="en_es")
    assert res.body().find("Hola")>0

    # more specific way of POSTing:
    res = s.POST_babelFormData_RETURNING_html(
                text="Hello world", languages="en_es")

Todo

Inclusions: wrdl:include/wrdl:import .

Full namespace support.

WRDL schemas in various schema languages.

Built-in support for building and splitting multipart/form-data, multipart/mixed, application/x-www-form-urlencoded' and perhaps even simple XML structures?

WRDL and REST Web Architecture

Hopefully the relationship between this specification and REST is becoming clear:

REST is defined by four interface constraints: identification of resources; manipulation of resources through representations; self-descriptive messages; and, hypermedia as the engine of application state.

These four things are addressed in this specification through:

On the Web, URIs are opaque. Therefore you should not think of your service having roots like /dothis or /dothat. There should be a single root XML document that represents your service. That is the only link that the client must know a priori. The rest the client boostraps by following links. That's why WRDL is resource and link centric, not URI centric.

Important Related Resources

If you are not familiar with the semantics of HTTP methods, you should read the definition in the HTTP specification. I would not spend much effort on understanding the methods other than PUT, POST, GET and DELETE, however.

One of WRDL's central goals is to promote an understanding of Web Architecture. Its design may make more sense if you read Tim Berners-Lee's axioms of Web Architecture.

Acknowledgements

Jason Diamond has provided some excellent ideas and much editorial commentary. WSDL created the impetus for a service description language compatible with web architecture, so thanks to its creators for providing inspiration.