lazr.restful's WADL documents
*****************************

Every resource in the web service has a WADL representation that
describes the capabilities of the resource in a machine-readable
format. These documents are similar to the HTML documents that provide
human beings with links to click and forms to fill out.

===============
Entry resources
===============

Let's get a WADL representation of an entry resource (in this case, a
cookbook), and see what's inside.

    >>> from urllib import quote
    >>> from lazr.restful.testing.webservice import WebServiceCaller
    >>> webservice = WebServiceCaller(domain='cookbooks.dev')
    >>> entry_url = quote("/cookbooks/The Joy of Cooking")
    >>> wadl = webservice.get(
    ...     entry_url, 'application/vnd.sun.wadl+xml').body

It's an XML document.

    >>> print wadl
    <?xml version="1.0"?>
    <wadl:application xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns="http://research.sun.com/wadl/2006/10"
        xmlns:wadl="http://research.sun.com/wadl/2006/10"
        xsi:schemaLocation="http://research.sun.com/wadl/2006/10/wadl.xsd">
    ...
    </wadl:application>

Let's parse it and make sure it validates against the WADL schema.

    >>> from lxml import etree
    >>> from lazr.restful import WADL_SCHEMA_FILE

    >>> wadl_schema = etree.XMLSchema(etree.parse(open(WADL_SCHEMA_FILE)))
    >>> from StringIO import StringIO
    >>> def validate(body):
    ...     res = wadl_schema.validate(
    ...         etree.parse(StringIO(body.decode('utf8'))))
    ...     if not res:
    ...         res = (res, wadl_schema.error_log)
    ...     return res
    ...
    >>> validate(wadl)
    True

    >>> tree = etree.fromstring(wadl)

The root tag of any WADL document is called 'application'. Note the
namespaced tag name; this test will be ignoring the namespace from
this point on.

    >>> tree.tag
    '{http://research.sun.com/wadl/2006/10}application'
    >>> def wadl_tag(tag):
    ...     """Return a WADL tag name properly namespace-qualified."""
    ...     return '{http://research.sun.com/wadl/2006/10}%s' % tag

The <application> tag for a WADL representation of an entry contains a
single <resources> tag.

    >>> def single_list_value(single_item_list):
    ...     msg = "Expected 1 value, but received %s" % len(single_item_list)
    ...     assert len(single_item_list) == 1, msg
    ...     return single_item_list[0]

    >>> resources = single_list_value(tree)
    >>> resources.tag
    '...resources'

The <resources> tag describes a set of resources rooted at the
person's URL.

    >>> resources.attrib['base']
    'http://.../The%20Joy%20of%20Cooking'

The <resources> tag contains a single <resource> tag. The WADL
description of a person describes only one resource: the person
itself.

    >>> resource = single_list_value(resources)
    >>> resource.tag
    '...resource'
    >>> resource.attrib['path']
    ''

What are the capabilities of this resource?

    >>> resource.attrib['type']
    'http://...#cookbook'

Since all cookbook resources work the same way, the capabilities of any
particular cookbook resource are described by reference to a separate
WADL document. This document is located at the service root (/),
and the part of the document that describes a person resource has the
XML id "cookbook". We'll look at this document later.

To summarize: the WADL representation of an entry is a very short XML
document that says "The resource at this URL is of type [foo]," where
[foo] is a reference to another WADL document.

====================
Collection resources
====================

The WADL description of a collection looks a lot like the WADL
description of an entry. It's an <application> tag that contains a
<resources> tag that contains a <resource> tag.

    >>> wadl = webservice.get('/cookbooks',
    ...                       'application/vnd.sun.wadl+xml').body
    >>> validate(wadl)
    True

    >>> tree = etree.fromstring(wadl)
    >>> tree.tag
    '...application'

    >>> resources = single_list_value(tree)
    >>> resources.tag
    '...resources'
    >>> resources.attrib['base']
    'http://.../cookbooks'

The <resource> tag defines the capabilities of the collection resource
by referencing another WADL document.

    >>> resource = single_list_value(resources)
    >>> resource.tag
    '...resource'
    >>> resource.attrib['path']
    ''
    >>> resource.attrib['type']
    'http://...#cookbooks'

===========================
Scoped collection resources
===========================

The WADL representation of a scoped collection is pretty similar to
the representation of a top-level collection.

    >>> wadl = webservice.get(entry_url + '/recipes',
    ...                       'application/vnd.sun.wadl+xml').body
    >>> validate(wadl)
    True

    >>> tree = etree.fromstring(wadl)
    >>> tree.tag
    '...application'

    >>> resources = single_list_value(tree)
    >>> resources.tag
    '...resources'
    >>> resources.attrib['base']
    'http://.../cookbooks/The%20Joy%20of%20Cooking/recipes'

    >>> resource = single_list_value(resources)
    >>> resource.attrib['path']
    ''
    >>> resource.attrib['type']
    'http://...#recipe-page-resource'

=====================
Hosted file resources
=====================

A hosted file resource is the web service's access point for a file
(usually a binary) hosted elsewhere. The most prominent hosted file in
the example web service is a cookbook's cover image.

A hosted file resource responds to GET requests by redirecting the
client to the externally hosted file. It responds to PUT or DELETE
requests by updating or deleting the underlying binary file.

The behavior laid out in the previous paragraph is also defined in the
WADL documents served by the web service itself. You can use content
negotiation to get a WADL description of any hosted file resource.

A cookbook starts out with no hosted cover, and an ordinary
GET to the place where the cover would be results in a 404 error.

    >>> print webservice.get(entry_url + '/cover')
    HTTP/1.1 404 Not Found
    ...

But if the client is interested in learning how to create a cover at
/cookbooks/Everyday%20Greens/cover, it can use content negotiation to
get a WADL description of the resource-to-be.

    >>> wadl = webservice.get(
    ...     entry_url + '/cover',
    ...     'application/vnd.sun.wadl+xml').body
    >>> validate(wadl)
    True

    >>> tree = etree.fromstring(wadl)

Just like with the WADL description of an entry or collection
resource, the WADL representation of a hosted file resource is not
much more than a reference to a big WADL file at the service root. To
find out about the capabilities of the resource-to-be, the client
needs to fetch the WADL representation of the service root and look
for the XML element with the ID "HostedFile".

    >>> tree.tag
    '...application'

    >>> resources = single_list_value(tree)
    >>> resources.tag
    '...resources'
    >>> resources.attrib['base']
    'http://.../The%20Joy%20of%20Cooking/cover'

    >>> resource = single_list_value(resources)
    >>> resource.tag
    '...resource'
    >>> resource.attrib['path']
    ''
    >>> resource.attrib['type']
    'http://...#HostedFile'

================
The service root
================

All the WADL documents we've seen so far have been very simple,
describing a single resource and describing it by reference to another
WADL document. That other document is the WADL representation of the
service root. It describes the capabilities of every kind of resource
the service offers. It also describes the JSON representations those
resources serve, and any custom methods invokable on those
resources. It's a big document.

    >>> wadl = webservice.get(
    ...     '/', 'application/vnd.sun.wadl+xml').body
    >>> validate(wadl)
    True
    >>> tree = etree.fromstring(wadl)

Like all WADL documents, the WADL representation of the service root
is rooted at an <application> tag.

    >>> tree.tag
    '...application'

As with the WADL descriptions of collection and entry resources, this
<application> tag describes the capabilities of the server root
resource. But that <application> tag also contains all the information
referenced by all the other WADL documents in the system. #PersonEntry
is here, as is #people and #ScopedCollection and
many other targets of a <resource> tag's 'resource_type' attribute. Also
located here are the descriptions of the JSON representations those
resources serve.

======================================
Description of the service root itself
======================================

Let's whittle down the complexity a little by taking a look at the
description of the service root resource itself.

    >>> from lxml.etree import _Comment
    >>> children = [child for child in tree
    ...             if not isinstance(child, _Comment)]
    >>> resources, service_root_type, service_root_repr = children[:3]
    >>> # We'll deal with the rest of the children later.
    >>> other_children = children[3:]

The service root is an instance of a special resource type that
responds only to GET.

    >>> service_root_type.tag
    '...resource_type'
    >>> service_root_type.attrib['id']
    'service-root'
    >>> (doc, get) = list(service_root_type)
    >>> get.tag
    '...method'
    >>> get.attrib['name']
    'GET'

A client that makes a GET request to a resource of this type can get a
representation of type 'service-root-json', or it can get a WADL
representation. The WADL representation is the document we're looking
at right now.

    >>> response = single_list_value(get)
    >>> json_repr, wadl_repr = list(response)
    >>> json_repr.attrib['href']
    '#service-root-json'
    >>> wadl_repr.attrib['mediaType']
    'application/vnd.sun.wadl+xml'

The details of the 'service-root-json' representation are given
immediately afterwards:

    >>> service_root_repr.tag
    '...representation'
    >>> service_root_repr.attrib['id']
    'service-root-json'
    >>> service_root_repr.attrib['mediaType']
    'application/json'

The JSON representation contains a link for each collection resource
exposed at the top level. The WADL representation has a <param> tag
for every link in the JSON representation.

    >>> def name_attrib(tag):
    ...     return tag.attrib['name']

    >>> params = sorted([param for param in service_root_repr],
    ...     key=name_attrib)
    >>> (cookbook_set_param, dish_set_param, featured_cookbook_param,
    ...  recipes_param, resource_type_param) = params
    >>> cookbook_set_param.tag
    '...param'
    >>> cookbook_set_param.attrib['name']
    'cookbooks_collection_link'
    >>> cookbook_set_param.attrib['path']
    "$['cookbooks_collection_link']"

    >>> featured_cookbook_param.tag
    '...param'
    >>> featured_cookbook_param.attrib['name']
    'featured_cookbook_link'
    >>> featured_cookbook_param.attrib['path']
    "$['featured_cookbook_link']"

    >>> resource_type_param.attrib['name']
    'resource_type_link'

    >>> resource_type_param.attrib['path']
    "$['resource_type_link']"

This is saying that applying the JSONPath expression
'$['cookbooks_collection_link']' to the JSON document will give you
something interesting: a variable we like to call
'cookbooks_collection_link'. Applying the JSONPath expression
'$['featured_cookbook_link']' will give you a variable we like to call
'featured_cookbook_link'.

What's special about these variables? Well, they're links to other
resources. This is represented in WADL by giving the <param> tag a
child <link> tag. The <link> tag explains what sort of resource is at
the other end of the link.

    >>> cookbook_set_param_link = single_list_value(cookbook_set_param)
    >>> cookbook_set_param_link.tag
    '...link'
    >>> cookbook_set_param_link.attrib['resource_type']
    'http://...#cookbooks'

    >>> featured_cookbook_param_link = single_list_value(
    ...     featured_cookbook_param)
    >>> featured_cookbook_param_link.tag
    '...link'
    >>> featured_cookbook_param_link.attrib['resource_type']
    'http://...#cookbook'

A WADL client can read this and know that if it ever finds a resource
of type "service-root", it can send a GET request to that URL and get
back a JSON document. By applying the JSON expression
'["cookbooks_collection_link"]' to that document, it will find the URL
to the list of cookbooks. By applying the JSON expression
'["featured_cookbook_collection_link"]' the client can find a URL that
will point to the currently featured cookbook.

The list of cookbooks has the characteristics described (in WADL
format) at http://...#cookbooks. A single cookbook has the
characteristics described at http://...#cookbook.

But where is the WADL client going to find a resource of type
"service-root" in the first place? The <resources> tag will explain
everything.

    >>> resources.tag
    '...resources'
    >>> print resources.attrib['base']
    http://cookbooks.dev/devel/

As with the <resources> tags shown earlier, this one contains a single
<resource> tag.

    >>> resource = single_list_value(resources)
    >>> resource.tag
    '...resource'
    >>> resource.attrib['path']
    ''
    >>> resource.attrib['type']
    '#service-root'

Aha! There's a resource of type "service-root" right there at the
service root! Who would have thought?

========================
The rest of the document
========================

Looking at the children of the <application> tag can be
overwhelming. The description of the service root resource is
relatively simple, but then there are a huge number of
<representation> and <resource_type> tags that don't have anything to
do directly with the service root: they form a description of the web
service as a whole. I'll explain the large-scale structure of the
document and then show some examples in detail.

The first few tags are <resource_type> tags which describe the
different possible kinds of top-level collections (cookbook
collections, dish collections, and so on). We'll look at those tags
first. Each type of collection resource has one tag devoted to it in
the WADL document:

1. A <resource_type> tag describing the HTTP requests a client can
   make to manipulate the collection resource. It might look like this::

     <resource_type id="CookbookCollection">
       <wadl:doc xmlns="http://www.w3.org/1999/xhtml/">
         A collection of cookbooks, as exposed through the web service.
       </wadl:doc>
       <method name="GET" id="CookbookCollection-get">
         <response>
           <representation href="http://.../#cookbook-page"/>
           <representation mediaType="application/vnd.sun.wadl+xml"
                           id="CookbookCollection-wadl"/>
         </response>
       </method>
     </resource_type>

We know we've reached the end of the collection resources when we see
a <resource_type> tag that supports the PUT method. Collections never
support PUT, so that must be an entry resource_type.

    >>> collection_resource_types = []
    >>> for index, child in enumerate(other_children):
    ...     put_method = [method for method in list(child)
    ...                   if method.tag.endswith("method")
    ...                   and method.attrib['name'] == 'PUT']
    ...     if len(put_method) > 0:
    ...         first_entry_type_index = index
    ...         break
    ...     collection_resource_types.append(child)

When we find a <resource_type> that supports PUT, we know that we've
come to the end of the collection resources and reached an entry
resource, like a recipe or cookbook. Each kind of entry resource has five
tags devoted to it in the WADL document:

1. A <resource_type> tag describing the HTTP requests a client can
   make to manipulate the entry resource. It might look like this::

     <resource_type id="message">
       <method name="GET" id="message-get">
         <response>
           <representation
            href="http://.../#message-full"/>
           <representation mediaType="application/vnd.sun.wadl+xml"
                           id="message-wadl"/>
         </response>
       </method>

       <method name="PUT" id="message-put">
         <request>
           <representation
            href="http://.../#message-full"/>
         </request>
       </method>

       <method name="PATCH" id="message-patch">
         <request>
           <representation
            href="http://.../#message-diff"/>
         </request>
      </method>

      <method name="DELETE" id="message-delete" />
     </resource_type>

2. A <representation> tag describing the document sent to the client
   in response to a GET request for the entry, and expected from the
   client along with a PUT request. This would be the
   "#message-full" referenced in the above WADL example.

3. A <representation> tag describing the document expected from the
   server along with a PATCH request. This would be the
   "#message-diff" referenced in the above WADL example.

4. A <resource_type> tag describing the capabilities of a page of a
   collection that contains this kind of entry. Some entry types may
   have both a top-level collection <resource_type> and a regular
   collection page <resource_type>. They need to be declared
   separately because top-level collections can have custom
   operations, and random collection pages can't. It might look like
   this::

     <resource_type id="message-page-resource">
       <method name="GET"
               id="message-page-resource-get">
         <response>
           <representation href="#message-page"/>
         </response>
       </method>
     </resource_type>

5. A <representation> tag describing the document sent to the client
   in response to a GET request for a collection. This includes
   top-level collections as well as scoped and other collections. This
   would be the "#message-page" referenced in the above
   WADL example, and the "#cookbook-page" referenced in the very
   first example.

(The last <resource_type> tag is a hard-coded description of a hosted
binary file resource. Since it's hard-coded, this test doesn't deal
with it.)

This code splits the tags into 5-tuples and stores the tuples in
'entry_resource_descriptions'.

    >>> entry_resource_descriptions = []
    >>> entry_resource_types = other_children[first_entry_type_index:-2]
    >>> hosted_binary_resource_type, simple_binary_type = other_children[-2:]
    >>> for index in range(0, len(entry_resource_types), 5):
    ...     entry_resource_descriptions.append(
    ...         (tuple(entry_resource_types[index:index + 5])))

Before looking at the descriptions of entry resources, we'll examine
the collection resource types.

==========================
A collection resource type
==========================

First let's look at the different collection resource types defined in the
WADL file, and their representations.

    >>> sorted([type.attrib['id'] for type in collection_resource_types])
    ['cookbooks', 'dishes', 'recipes']

There's one <resource_type> tag for every top-level collection on the
site. We'll be taking a close look at the resource type for the
site's collection of cookbooks.

    >>> resource_type = single_list_value([
    ...     type for type in collection_resource_types
    ...     if type.attrib['id'] == 'cookbooks'])

    >>> resource_type.tag
    '...resource_type'

Any collection resource supports one standard HTTP method (GET) in
addition to any custom operations.  This particular collection
resource is the top-level list of cookbooks, and it exposes a few other
custom operations.

    >>> methods = resource_type.findall(wadl_tag('method'))
    >>> sorted((method.attrib['name'], method.attrib['id'])
    ...        for method in methods)
    [('GET', 'cookbooks-find_for_cuisine'),
     ('GET', 'cookbooks-find_recipes'),
     ('GET', 'cookbooks-get'),
     ('POST', 'cookbooks-create')]
    >>> (create, find_for_cuisine, find_recipes, get) = sorted(
    ...     methods, key=lambda i: i.attrib['id'])

The standard GET operation is a way of getting either a page of the
collection (see "The representation of a collection" later in this
test) or else a short WADL description of a particular collection,
like the one shown earlier in this test.

    >>> response = single_list_value(get)
    >>> json_rep, wadl_rep = list(response)
    >>> json_rep.attrib['href']
    'http://...#cookbook-page'

    >>> wadl_rep.attrib['mediaType']
    'application/vnd.sun.wadl+xml'
    >>> wadl_rep.attrib['id']
    'cookbooks-wadl'

Operation parameters
====================

The <method> tag for a named operation will contain one or more
<parameter> tags describing the parameters the operation accepts. The
'create' custom operation takes a number of parameters.

    >>> create_request = create.find(wadl_tag('request'))
    >>> create_response = create.find(wadl_tag('response'))
    >>> create_representation = single_list_value(create_request)
    >>> sorted([param.attrib['name'] for param in create_representation])
    ['copyright_date', 'cuisine', 'description', 'last_printing',
     'name', 'price', 'ws.op']

The 'ws.op' parameter is present for every named operation, and has a
fixed value: the name of the operation.

    >>> ws_op = create_representation[0]
    >>> ws_op.attrib['fixed']
    'create'

The 'create' custom operation also defines a return value. When you
invoke that operation the Location header of the response is a link to
the newly created cookbook.

    >>> create_response_param = single_list_value(create_response)
    >>> create_response_param.attrib['style']
    'header'
    >>> create_response_param.attrib['name']
    'Location'

    >>> create_response_param_link = single_list_value(
    ...     create_response_param)
    >>> create_response_param_link.attrib['resource_type']
    'http://...#cookbook'

The 'find_recipes' custom operation accepts one parameter in addition
to 'ws.op'.

    >>> find_request = find_recipes.find(wadl_tag('request'))
    >>> find_response = find_recipes.find(wadl_tag('response'))
    >>> [param.attrib['name'] for param in find_request]
    ['ws.op', 'vegetarian', 'search']

    >>> ws_op = find_request[0]
    >>> ws_op.attrib['fixed']
    'find_recipes'

The 'find_recipes' custom operation returns a collection of recipes.

    >>> find_response_representation = single_list_value(find_response)
    >>> find_response_representation.attrib['href']
    'http://...#recipe-page'

======================
An entry resource type
======================

Now let's look at how the service root WADL describes entry
resources.

    >>> sorted([entry[0].attrib['id']
    ...         for entry in entry_resource_descriptions])
    ['cookbook', 'cookbook_subclass', 'dish', 'recipe']

There's one <resource_type> tag for every kind of entry on the
site. Let's take a close look at the WADL description of a cookbook.

    >>> cookbook_description = [entry for entry in entry_resource_descriptions
    ...                         if entry[0].attrib['id'] == 'cookbook'][0]

    >>> (entry_type, full_rep, diff_rep,
    ...  collection_type, collection_rep) = cookbook_description

=====================
Entry representations
=====================

The definition of a cookbook is contained in a <resource_type> tag and
two <representation> tags. First lets look at the two
representations. Each <representation> tag specifies what media type
it's describing. Both of these <representation> tags describe JSON
documents.

    >>> full_rep.tag
    '...representation'
    >>> full_rep.attrib['mediaType']
    'application/json'
    >>> full_rep.attrib['id']
    'cookbook-full'

    >>> diff_rep.tag
    '...representation'
    >>> diff_rep.attrib['mediaType']
    'application/json'
    >>> diff_rep.attrib['id']
    'cookbook-diff'

Representation parameters
=========================

An earlier section showed how <method> tags could contain <param> tags
describing the parameters to a custom operation. A <representation>
tag may also contain <parameter> tags that point clients to
interesting parts of the representation. Our JSON representations of
entries are hashes, and we've chosen to specify a parameter for each
key of the hash.

    >>> full_params = list(full_rep)
    >>> full_params[0].tag
    '...param'
    >>> full_rep_names = sorted([param.attrib['name']
    ...                         for param in full_params])
    >>> full_rep_names
    ['confirmed', 'copyright_date', ..., 'self_link']

In addition to a name, each representation parameter has a 'path', a
JSONPath expression you can apply to the JSON data structure to get
the parameter's value.

    >>> sorted([param.attrib['path'] for param in full_params])
    [..., "$['cuisine']", ... "$['self_link']"]

So to get the cuisine out of a JSON data structure you need to
look up the element called "cuisine".

Just as with operation parameters, a representation parameter may have
an optional data type.

    >>> copyright_date = single_list_value(
    ...     [param for param in full_params
    ...      if param.attrib['name'] == 'copyright_date'])
    >>> copyright_date.attrib['type']
    'xsd:date'

As with operation parameters, the default is "xsd:string".

    >>> cuisine = single_list_value([param for param in full_params
    ...                             if param.attrib['name'] == 'cuisine'])
    >>> 'type' in cuisine.attrib
    False

A parameter may also have human-readable documentation: an optional
name for the parameter and an optional short description.

    >>> doc = copyright_date[0]
    >>> doc.tag
    '...doc'
    >>> print "\n".join([node.text for node in doc])
    Copyright Date
    The copyright date for this work.

Every entry resource has the 'http_etag' parameter, which includes the
current value used in the 'ETag' HTTP header for the entry.

    >>> [etag] = [param for param in full_params
    ...           if param.attrib['name'] == 'http_etag']
    >>> etag.attrib['path']
    "$['http_etag']"

Some parameters are links to other resources. These parameters have a
child tag called 'link' with information about what's on the other end
of the link.

    >>> recipes = single_list_value([
    ...     param for param in full_params
    ...     if param.attrib['name'] == 'recipes_collection_link'])
    >>> doc, recipes_link = recipes.getchildren()
    >>> recipes_link.tag
    '...link'

The link's 'resource_type' attribute tells the client about the
capabilities of the resource at the other end of the link.  For
example, the list of a cookbook's recipes is a collection of recipes.

    >>> recipes_link.attrib['resource_type']
    'http://...#recipe-page-resource'

A link parameter may also link to one specific resource. For instance,
each recipe links to one dish. This is represented in WADL by a
'dish_link' parameter.

    >>> recipe_description = [entry for entry in entry_resource_descriptions
    ...                       if entry[0].attrib['id'] == 'recipe'][0]
    >>> recipe_params = list(recipe_description)[1]

    >>> [dish_param] = [param for param in recipe_params
    ...                 if param.attrib['name'] == 'dish_link']
    >>> dish_link = dish_param[1]
    >>> dish_link.tag
    '...link'

The dish_link's 'resource_type' indicates that the thing on the other
end of the link is a dish.

    >>> dish_link.attrib['resource_type']
    'http://...#dish'

The full representation contains all fields, even read-only ones,
because it's describing the document you receive when you make a GET
request. You can modify such a document and send it back with PUT, so
the full representation also suffices to describe the documents you
PUT. But you can't send values for read-only fields with PATCH, so we
define a second representation for use with PATCH requests.

    >>> diff_params = list(diff_rep)
    >>> diff_params[0].tag
    '...param'
    >>> diff_rep_names = sorted([param.attrib['name']
    ...                          for param in diff_params])

    >>> 'self_link' in full_rep_names
    True
    >>> 'self_link' in diff_rep_names
    False
    >>> 'resource_type_link' in full_rep_names
    True
    >>> 'resource_type_link' in diff_rep_names
    False
    >>> 'recipes_collection_link' in full_rep_names
    True
    >>> 'recipes_collection_link' in diff_rep_names
    False

Fields that have server-side mutators are considered read-write
fields, and show up in the PATCH representation.

    >>> 'cuisine' in diff_rep_names
    True

Fields marked read-only show up in the PUT representation but not the
PATCH representation.

    >>> 'copyright_date' in full_rep_names
    True
    >>> 'copyright_date' in diff_rep_names
    False

Most <param> tags don't tell the client much beyond where to find a
certain parameter, but some of our parameters take values from a
proscribed vocabulary. These parameters correspond to Choice fields
who take their vocabulary from an EnumeratedValue. For these
parameters, the server provides the client with information about the
possible values.

    >>> cuisine_param = single_list_value(
    ...     [param for param in full_params
    ...      if param.attrib['name'] == 'cuisine'])
    >>> cuisine_options = cuisine_param.getchildren()
    >>> cuisine_options[0].tag
    '...doc'
    >>> cuisine_options[1].tag
    '...option'
    >>> sorted(status.attrib['value'] for status in cuisine_options[1:])
    ['American', ... 'General', 'Vegetarian']


Parameter data types
====================

Operation and representation parameters are always transfered between
client and server as strings. But a parameter may have a logical data
type which indicates how to treat the string. Data types are specified
using the primitive types from the XML Schema standard.

Here's a parameter of type 'date'.

    >>> copyright_date = single_list_value(
    ...     [param for param in create_representation
    ...      if param.attrib.get('name') == 'copyright_date'])
    >>> copyright_date.attrib['type']
    'xsd:date'

Here's a parameter of type 'binary'.

    >>> cover = single_list_value(
    ...     [param for param in full_rep
    ...      if param.attrib.get('name') == 'cover_link'])
    >>> cover.attrib['type']
    'binary'

If no data type is provided, the WADL standard says to default to
"xsd:string". This is the case for the vast majority of parameters.

    >>> cuisine = single_list_value(
    ...     [param for param in create_representation
    ...           if param.attrib.get('name') == 'cuisine'])

    >>> 'type' in cuisine.attrib
    False

If a parameter represents a choice among several options, it might be
described with a list of valid values. The "cuisine" parameter is a
choice among several preset values, and the WADL describes those
values.

    >>> values = cuisine[1:]
    >>> sorted([value.attrib['value'] for value in values])
    ['American', ... 'Vegetarian']

Here's the same field for a named operation.

    >>> doc, request, response = list(find_for_cuisine)
    >>> ws_op, cuisine = list(request)
    >>> values = cuisine[1:]
    >>> sorted([value.attrib['value'] for value in values])
    ['American', ... 'Vegetarian']

The entry resource type itself
==============================

The 'representation' tags tell you what representations a resource
sends and receives. In this case the representations are for a
'bugtask' resource. What about the resource itself? All bug tasks are
pretty much the same, and so most of the information about a bug task
is kept in the <resource_type> tag.

    >>> entry_type.tag
    '...resource_type'

    >>> def sort_by_id(method):
    ...     return method.attrib['id']
    >>> methods = sorted(
    ...     entry_type.findall(wadl_tag('method')), key=sort_by_id)
    >>> (findRecipeFor, findRecipes, get, makeMoreInteresting, patch,
    ...  put, replace_cover) = methods

A resource type tells the client about the four standard operations on
a resource (GET, PUT, PATCH, and possibly DELETE), as well as any
custom GET or POST operations.

The name of a method is always the HTTP method used to activate
it. Different operations that use the same method are distinguished by
XML id. Here that's not a problem; we have one custom POST method
('bug_task-transitionToStatus'), plus the standard GET, PATCH, and PUT.

    >>> sorted((method.attrib['name'], method.attrib['id'])
    ...        for method in methods)
    [('GET', 'cookbook-find_recipe_for'),
     ('GET', 'cookbook-find_recipes'),
     ('GET', 'cookbook-get'),
     ('PATCH', 'cookbook-patch'),
     ('POST', 'cookbook-make_more_interesting'),
     ('POST', 'cookbook-replace_cover'),
     ('PUT', 'cookbook-put')]

Standard entry operations
=========================

The standard GET operation defines a 'response' tag, which tells the
client that they can use content negotiation to get three different
representations of a bug task: the JSON one described above as
"BugTask-full", an XHTML snippet, and a WADL document--the sort of
document shown in the very first section of this test.

    >>> response = get.find(wadl_tag('response'))
    >>> response.tag
    '...response'
    >>> full, html, wadl = list(response)
    >>> full.attrib['href']
    'http://...#cookbook-full'

    >>> html.attrib['id']
    'cookbook-xhtml'
    >>> html.attrib['mediaType']
    'application/xhtml+xml'

    >>> wadl.attrib['id']
    'cookbook-wadl'
    >>> wadl.attrib['mediaType']
    'application/vnd.sun.wadl+xml'

Note that the JSON representation is just a hyperlink to the
representation defined earlier.

Similarly, the standard PUT and PATCH methods each include a 'request'
tag, which tells the client which representation it should send along
with a request.

    >>> request = single_list_value(put)
    >>> request.tag
    '...request'
    >>> representation = single_list_value(request)
    >>> representation.attrib['href']
    'http://...#cookbook-full'

    >>> response = single_list_value(patch)
    >>> representation = single_list_value(response)
    >>> representation.attrib['href']
    'http://...#cookbook-diff'

This is why we defined the representations separately. Now we can
link to them instead of describing them every time.

Some entries support DELETE. In this example, cookbook entries can't
be deleted, but recipe entries can.

    >>> recipe_description = [entry for entry in entry_resource_descriptions
    ...                       if entry[0].attrib['id'] == 'recipe'][0]

    >>> recipe_type = recipe_description[0]

    >>> methods = sorted(
    ...     recipe_type.findall(wadl_tag('method')), key=sort_by_id)
    >>> (delete, get, patch, put) = methods
    >>> delete.attrib['id']
    'recipe-delete'

DELETE is a very simple HTTP method that takes no payload and returns
nothing, so there's nothing inside this tag. It's just a flag that
this resource type supports DELETE.

Custom operations
=================

Custom operations activated with GET may have URL parameters.

    >>> get_request = findRecipes.find(wadl_tag('request'))
    >>> [param.attrib['name'] for param in get_request]
    ['ws.op', 'search']

Custom operations activated with POST may have a form-encoded or
multipart representation. If the operation has no binary parameters,
the recommended content type is application/x-www-form-urlencoded.

    >>> post_request = makeMoreInteresting.find(wadl_tag('request'))
    >>> post_representation = post_request.find(wadl_tag('representation'))
    >>> post_representation.attrib['mediaType']
    'application/x-www-form-urlencoded'
    >>> [param.attrib['name'] for param in post_representation]
    ['ws.op']

If the operation has a binary parameter, the recommended content type
is multipart/form-data.

    >>> binary_post_request = replace_cover.find(wadl_tag('request'))
    >>> binary_post_representation = binary_post_request.find(
    ...     wadl_tag('representation'))
    >>> binary_post_representation.attrib['mediaType']
    'multipart/form-data'

The 'ws.op' parameter is present for all custom operations, either as
a URL parameter or as part of the representation. It's always
required, and fixed to a particular value.

    >>> ws_op = single_list_value(post_representation)
    >>> ws_op.attrib['required']
    'true'
    >>> ws_op.attrib['fixed']
    'make_more_interesting'

=====================
Hosted file resources
=====================

One interesting type of parameter not shown above is a link to an
externally hosted file managed by the web service, such as a
cookbook's cover.

    >>> cover_param = single_list_value(
    ...     [param for param in full_rep
    ...      if param.attrib['name'] == 'cover_link'])
    >>> doc, cover_link = cover_param
    >>> cover_link.attrib['resource_type']
    'http://...#HostedFile'

What can the client do to this hosted file resource?

    >>> get, put, delete = list(hosted_binary_resource_type)

The client can send GET to the resource, and be redirected to a file
hosted externally.

    >>> get.tag
    '...method'
    >>> get.attrib['name']
    'GET'
    >>> get_response = single_list_value(get)
    >>> get_representation = single_list_value(get_response)
    >>> get_representation.attrib['status']
    '303'
    >>> redirect_param = single_list_value(get_representation)
    >>> redirect_param.tag
    '...param'
    >>> redirect_param.attrib['style']
    'header'
    >>> redirect_param.attrib['name']
    'Location'

The client can PUT a hosted file:

    >>> put.tag
    '...method'
    >>> put.attrib['name']
    'PUT'

The client can DELETE an existing file:

    >>> delete.tag
    '...method'
    >>> delete.attrib['name']
    'DELETE'

========================================
A non-top-level collection resource type
========================================

We're almost done with our in-depth look at the WADL description of a
cookbook. Now we need to consider a page of cookbooks. This is
different from the top-level collection of cookbooks because a
top-level collection can have custom operations. A "page of cookbooks"
resource only supports the standard GET operation. The "page of
cookbooks" might be served from a scoped collection (the collection of
cookbooks owned by a user), a named operation (search for cookbooks by
cuisine), or by following the 'next' link from a top-level collection.

This <resource_type> describes a list of cookbooks.

    >>> collection_type.tag
    '...resource_type'
    >>> collection_type.attrib['id']
    'cookbook-page-resource'

The only method supported is the standard GET.

    >>> get = single_list_value(collection_type)
    >>> get.attrib['id']
    'cookbook-page-resource-get'

In response to the standard GET operation, collection resources will
serve a JSON representation, described immediately below.

    >>> get_response = single_list_value(get)
    >>> json_representation = single_list_value(get_response)
    >>> json_representation.attrib['href']
    '#cookbook-page'

==================================
The representation of a collection
==================================

The representation of one type of entry (say, a cookbook) looks very
different from the representation of another type (say, a recipe), but
all collections look pretty much the same, no matter what kind of
entries they contain. In fact, a top-level collection (say, the
collection of recipes) references the same <representation> tag as a
corresponding scoped collection (say, the recipes in a cookbook) or
any other collection (say, the second page of the top-level recipe
collection).

    >>> collection_rep.tag
    '...representation'
    >>> collection_rep.attrib['mediaType']
    'application/json'

All collection representations have the same five <param> tags.

    >>> [param.attrib['name'] for param in collection_rep]
    ['resource_type_link', 'total_size', 'start', 'next_collection_link',
     'prev_collection_link', 'entries', 'entry_links']
    >>> (type_link, size, start, next, prev, entries,
    ...  entry_links) = collection_rep

So what's the difference between a collection of people and a
collection of bug tasks? Well, the ID is different, but that's just a
name.

    >>> collection_rep.attrib['id']
    'cookbook-page'

No, the real difference is the 'entry_links' parameter. It tells the
client that this particular collection contains links to objects of
type 'cookbook'.

    >>> entry_links.attrib['path']
    "$['entries'][*]['self_link']"
    >>> link = single_list_value(entry_links)
    >>> link.attrib['resource_type']
    'http://...#cookbook'

This tells the client that a 'collection of cookbooks' resource
contains lots of links to 'cookbook' resources.

The 'next_collection_link' and 'prev_collection_link' parameters are
also links to other resources. What are these other resources? Other
pages of the same collection!

    >>> next_type = single_list_value(next)
    >>> next_type.attrib['resource_type']
    '#cookbook-page-resource'

    >>> prev_type = single_list_value(prev)
    >>> prev_type.attrib['resource_type']
    '#cookbook-page-resource'

Misspelled media type
=====================

Earlier versions of lazr.restful served WADL documents with a
misspelled media type. For purposes of backwards compatibility, a
client can still request this media type, and lazr.restful will serve
a standard WADL document with a misspelled Content-Type.

    >>> misspelling = 'application/vd.sun.wadl+xml'
    >>> misspelled_response = webservice.get("/", misspelling)
    >>> misspelled_response.getHeader("Content-Type") == misspelling
    True

    >>> wadl_from_misspelled_response = misspelled_response.body
    >>> validate(wadl_from_misspelled_response)
    True

This works with any kind of resource you might request the WADL for:
the service root, an entry resource, or a hosted binary file resource.

    >>> misspelled_response = webservice.get(entry_url, misspelling)
    >>> misspelled_response.getHeader("Content-Type") == misspelling
    True

    >>> misspelled_response = webservice.get(
    ...     entry_url + "/cover", misspelling)
    >>> misspelled_response.getHeader("Content-Type") == misspelling
    True
