Skip to content
Dynamic, framework-neutral metadata describing path/URI structures, with natural translations to/from JSON, YAML and XML. Bonus feature: a plain text report format!
Python
Find file
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Failed to load latest commit information.
LICENSE
README.rdoc
described_routes.py
uri_template.py

README.rdoc

described_routes

DESCRIPTION

Dynamic, framework-neutral metadata describing path/URI structures natively in Python and through JSON, YAML and XML representations.

Its purpose is to define and support a metadata format capable of being generated dynamically from web applications, describing the URI structure of the application in its entirety or of specific resources and their related subresources. In a very lightweight manner - focussed only on resource identification - it aims to cover a spectrum ranging from application description languages (cf WSDL and WADL) through to more dynamic, hyperlinked interaction (cf REST and HATEOAS).

See roadmap for the original Ruby-based described_routes and path-to at positiveincline.com/?p=213.

CONTENTS

  • EXAMPLES

    • Converting to and from JSON and YAML

    • Plain text representation

    • XML

    • Basic URI and path generation

    • Dynamic partial template expansion

  • DATA STRUCTURE

    • Attributes

    • Navigation

  • REQUIREMENTS

  • AUTHOR AND CONTACT INFORMATION

EXAMPLES

Converting to and from JSON and YAML

The ResourceTemplate and ResourceTemplates classes have constructors that can take native Python dicts and lists (of dicts or of ResourceTemplate objects), so that converting to and from JSON and YAML is very straightforward. For example (with output edited for brevity and formatting), JSON conversions look like this:

>>> import json
>>> user = ResourceTemplate(json.loads(user_json))
>>> print json.dumps(user.to_dict())
{
  "name": "user", 
  "uri_template": "http://example.com/users/{user_id}{-prefix|.|format}", 
  "params": ["user_id"], 
  "optional_params": ["format"], 
  "options": ["GET", "PUT", "DELETE"],
  "resource_templates": [
    {
      "name": "edit_user", 
      "rel": "edit", 
      "uri_template": "http://example.com/users/{user_id}/edit{-prefix|.|format}", 
      "params": ["user_id"], 
      "optional_params": ["format"], 
      "options": ["GET"]
    }, 
    {
      "name": "user_articles", 
      "rel": "articles", 
      "uri_template": "http://example.com/users/{user_id}/articles{-prefix|.|format}", 
      "params": ["user_id"], 
      "optional_params": ["format"], 
      "options": ["GET", "POST"]
    }
  ] 
}

This (or something very much like it) should work with your favourite JSON module; YAML similarly.

Plain text representation

ResourceTemplate and ResourceTemplates objects print as follows (using a more complete example):

>>> print users
users                  users                GET, POST              http://example.com/users{-prefix|.|format}
  new_user             new_user             GET                    http://example.com/users/new{-prefix|.|format}
  {user_id}            user                 GET, PUT, DELETE       http://example.com/users/{user_id}{-prefix|.|format}
    edit               edit_user            GET                    http://example.com/users/{user_id}/edit{-prefix|.|format}
    articles           user_articles        GET, POST              http://example.com/users/{user_id}/articles{-prefix|.|format}
      new_user_article new_user_article     GET                    http://example.com/users/{user_id}/articles/new{-prefix|.|format}
      recent           recent_user_articles GET                    http://example.com/users/{user_id}/articles/recent{-prefix|.|format}
      {article_id}     user_article         GET, PUT, DELETE       http://example.com/users/{user_id}/articles/{article_id}{-prefix|.|format}
        edit           edit_user_article    GET                    http://example.com/users/{user_id}/articles/{article_id}/edit{-prefix|.|format}
    profile            user_profile         GET, PUT, DELETE, POST http://example.com/users/{user_id}/profile{-prefix|.|format}
      edit             edit_user_profile    GET                    http://example.com/users/{user_id}/profile/edit{-prefix|.|format}
      new              new_user_profile     GET                    http://example.com/users/{user_id}/profile/new{-prefix|.|format}

XML

not yet implemented in Python

This follows the natural structure but with the following modifications:

  • A ResourceTemplate element for each resource template

  • A ResourceTemplates element for each list of resources (top level or subresources)

  • Params and OptionalParams elements for params and optional_params, each containing param elements

  • A single options element contains the applicable HTTP methods as a comma-separated list

Basic URI and path generation

URIs and paths can be generated for specific resources, given a dict of actual parameters:

>>> actual_params = {"user_id": "dojo", "format": "json"}
>>> users.uri_for({"user_id": "dojo", "format": "json"})
"http://example.com/users/dojo.json"
>>> users.path_for({"user_id": "dojo", "format": "json"})
"/users/dojo.json"

Where the resource template has a path_template but no uri_template, a base parameter may be supplied to the uri_for() method.

Dynamic partial template expansion

ResourceTemplate objects can be parameterised as shown below. The effect of this is to define a “mini application” around a concrete resource of set of resources, supporting a more dynamic, hyperlinked style.

>>> actual_params = {"user_id": "dojo", "format": "json"}
>>> print user.partial_expand(actual_params)
user                 user                 GET, PUT, DELETE       http://example.com/users/dojo.json
  edit               edit_user            GET                    http://example.com/users/dojo/edit.json
  articles           user_articles        GET, POST              http://example.com/users/dojo/articles.json
    new_user_article new_user_article     GET                    http://example.com/users/dojo/articles/new.json
    recent           recent_user_articles GET                    http://example.com/users/dojo/articles/recent.json
    {article_id}     user_article         GET, PUT, DELETE       http://example.com/users/dojo/articles/{article_id}.json
      edit           edit_user_article    GET                    http://example.com/users/dojo/articles/{article_id}/edit.json
  profile            user_profile         GET, PUT, DELETE, POST http://example.com/users/dojo/profile.json
    edit             edit_user_profile    GET                    http://example.com/users/dojo/profile/edit.json
    new              new_user_profile     GET                    http://example.com/users/dojo/profile/new.json

DATA STRUCTURE

Attributes

A ResourceTemplate object has the following attributes:

name

An application-wide identifier

rel

An indication of a child resource's relationship to its parent

path_template

A template for the resource's path, in the style of URI Template but as a relative path

uri_template

A template for the resource's URI (generated only if the root URI is known at generation time)

params

A list of parameters required by path_template

optional_params

A list of optional parameters that may be incorporated by the path_template

options

A list of HTTP methods supported by the resource

resource_templates

A list of ResourceTemplate objects, implemented by the ResourceTemplates class

All attributes are optional; empty or blank attributes are omitted in external representations.

By convention, members of collections identified by key attributes don't have a rel attribute. In the examples above, the user template has children named edit_user and user_articles with rel attributes of “edit” and “articles” respectively, but the user_article child of user_articles has none, as it is identified relative to its parent by an article_id parameter.

Navigation

These data structures (trees or list of trees) can be traversed by iterating through the ResourceTemplate members of ResourceTemplates objects, which might be at the top level or the resource_templates attribute of a ResourceTemplate object.

Two methods support navigation by name or by rel:

1) <code>ResourceTemplates.all_by_name()<code>: this returns a memoized dict of all ResourceTemplate objects in or below the ResourceTemplates collection

2) ResourceTemplate.find_by_rel(rel): this returns a list of all ResourceTemplate objects that are direct descendants of the target ResourceTemplate and have a rel attribute equal to the one the supplied (which may take the value None).

REQUIREMENTS

Joe Gregorio's URI Template parser (to be found at code.google.com/p/uri-templates/source/browse/#svn/trunk).

Your favourite JSON or YAML printer/parser.

AUTHOR AND CONTACT INFORMATION

Mike Burrows (asplake), email mjb@asplake.co.uk, website positiveincline.com (see articles tagged described_routes)

Something went wrong with that request. Please try again.