In the words of Mark Nottingham:
CORBA has IDL; SOAP has WSDL. Developers often ask for similar capabilites for HTTP-based, "RESTful" services. While WSDL does claim support for HTTP, isn't well-positioned to take advantage of HTTP's features, nor to encourage good practice.
WADL is designed to fill this gap. It is HTTP-centric and attempts to provide a straightforward syntax for describing the semantics of particular methods on resources.
Resources and SOA
Resources are a key concept in REST, and also in REST-style SOA. A service expresses its interface as a set of resources. All resources share the same Uniform Contract. However, different resources have different associated semantics.
Resources effectively replace the traditional service-specific contract in a SOA. In doing so they introduce a meta-data gap. Where the contract previously described the interface to the service in a single coherent place, the Uniform Contract of resources does little to describe the interface of a given service.
Filling this gap is an important part of applying the REST style to SOA. This occurs in two parts: One part is the application of additional hypermedia so that clients can locate the correct resource to invoke requests upon based on the information that they are likely to have at hand. This hypermedia is incorporated into the Uniform Contract in terms of defined link relationship types and dedicated hypermedia-intensive media types. The second part is the context where WADL can be applied, and is incorporated into the service description.
Objectives of WADL in SOA
The kind of machine-readable description WADL could offer is required to fulfil a number of specific needs:
- Discovery of services by solution designers for potential reuse (Service Discoverability Principle)
- Express service interface to Enterprise Architecture Team for review and governance
- Basis for service implementation (Contract-first design becomes Resources-first design)
- Basis for service-side tooling (Tools to map resource capabilities onto core service logic)
- Basis for service support and ongoing maintenance
The information is not fundamentally for service consumer consumption beyond a basic level of discovery. Importantly, knowledge of relationships between resources should not normally be known by service consumers ahead of time. Consumers should make use of links between resources to discover relationships. Failure to adhere to this principle undoes a number of REST features such as the ability to link freely from one service to another with confidence that service consumers will successfully discover and exploit the specified resource at runtime.
Key Resource Metadata
I tend to look on the kind of interface description needed at this level as more of a table than a tree. I think that it is generally advisable to include most of the path when describing the semantics of methods on a given resource. Nevertheless, XML is adequate to describe this structure. I would tend to include the following features:
- List service-specific resource identifiers - Will often incorporate identifier templates
- Describe the semantics of each uniform method on the resource
- List the alternative media types that can be used for each (resource, method) pair. Each alternative is supported, and the specific type negotiated at run-time
- Include resources with hyperlinks to discover resources at run-time
- Identify key entry points for the total set of resources
An example description in table format might be:
Base URL | https://invoice.example.com | |||
---|---|---|---|---|
Resource Identification | Method (Uniform) | Media Types (Uniform) | Cache | Documentation |
/{invoice id} | GET |
|
Must revalidate | Retrieve invoice for invoice id |
PUT |
|
No cache | Update Invoice for invoice id to match specified state | |
/{invoice id}/payment/ | POST |
|
No cache | Add a payment relating to this invoice |
/{invoice id}/payment/{trans id} | GET |
|
5 minutes | Fetch a specific transaction for this invoice |
/?[date=]&[customer=]&[paid=] | GET |
|
Must-revalidate | Query for invoices with specified properties |
Each line describes a set of resources corresponding to the URL template. The template is filled out with parameters that the server will interpret when the request is processed. URLs can be seen as a message from the service to itself. It should not generally be parsed outside of the service, nor constructed outside of the service. I tend to use the query convention in the last URL template to indicate this rule is being broken and explicit service/consumer coupling is being introduced.
Methods and Media Types are referred to by their identifier only. There is no need to include them in a service description, because they should already be adequately described in uniform contract specification documents. Supporting multiple media types for a given method is important in an architecture with an evolving set of media types. It allows old services and consumers to continue to interact with new ones over the transition period without having to perform simultaneous upgrade.
Cache is also important, as this is a key REST constraint that needs to be described to support governance activities in compliance with the constraint.
While nesting exists to a point, there is no strongly-implied relationship between different nested or non-nested URLs. Each resource has its own distinct semantics. Hypermedia is incorporated into multiple resources by way of links embedded in invoice representations. For example, invoices are likely to include a link to the customer entity that the invoice was made out to. The set above also includes hypermedia in the form of query URLs that a service consumer who has a number of starting parameters can use to find the invoices they want.
Applying WADL to the problem
The WADL equivalent for the above service metadata is follows:
<application xmlns="http://research.sun.com/wadl/2006/10" xmlns:html="http://www.w3.org/1999/xhtml" xmlns:xsd="http://www.w3.org/2001/XMLSchema" > <doc> <html:p>Meta-data for the Invoice service, corresponding to the <html:a href="https://example.com/interface-control/resource"> example.com uniform interface</html:a> </html:p> </doc> <resources base="https://invoice.example.com"> <resource path="/{invoice-id}"> <param name="invoice-id" style="template" type="xsd:NMTOKEN"/> <method name="GET"> <doc><html:p>Retrieve invoice for invoice-id</html:p></doc> <response> <representation mediaType="application/vnd.com.example..invoice+xml"/> <representation mediaType="application/vnd.com.visa..invoice+xml"/> </response> </method> <method name="PUT"> <doc><html:p>Update Invoice for invoice id to match specified state</html:p></doc> <response> <representation mediaType="application/vnd.com.example..invoice+xml"/> </response> </method> </resource> <resource path="/{invoice-id}/payment/"> <param name="invoice-id" style="template" type="xsd:NMTOKEN"/> <method name="POST"> <doc><html:p>Add a payment relating to this invoice</html:p></doc> <response> <representation mediaType="application/ebxml.transaction+xml"/> </response> </method> </resource> <resource path="/{invoice-id}/payment/{trans-id}"> <param name="invoice-id" style="template" type="xsd:NMTOKEN"/> <param name="trans-id" style="template" type="xsd:NMTOKEN"/> <method name="GET"> <doc><html:p>Fetch a specific transaction for this invoice</html:p></doc> <response> <representation mediaType="application/ebxml.transaction+xml"/> </response> </method> </resource> <resource path="/"> <param name="date" style="query" required="false" type="xsd:dateTime" /> <param name="customer" style="query" required="false" type="xsd:anyURI" /> <param name="paid" style="query" required="false" type="xsd:boolean" /> <method name="GET"> <doc><html:p>Query for invoices with specified properties</html:p></doc> <response> <representation mediaType="application/ebxml.transaction+xml"/> </response> </method> </resource> </resources> </application>
That actually wasn't too painful. It was easy enough to mimic the table structure. I think this makes the description of a resource more readable. It handled the various parameters to these URLs in a straightforward way. The only thing really missing from this description is the caching information from our earlier table.
Conclusion
I think WADL is more or less suitable as a machine-readable media type for describing the set or resources exposed by a service. It could perhaps do with some extensions (and better extensibility), but it seems like a good starting point to me.
I have written about WADL from a slightly different perspective previously.
Benjamin