Source

described_routes /

Filename Size Date modified Message
described_routes
tests
356 B
1.1 KB
9.5 KB
32 B
899 B

DescribedRoutes

DESCRIPTION

Dynamic, framework-neutral metadata describing path/URI structures with text and JSON representations.

For server apps built on Routes-based frameworks (e.g. Pylons), a wsgi middleware component described_routes.routes.DescribedRoutesMiddleware converts and publishes the Routes Mapper structure and adds link headers to facilitate their auto-discovery.

For the client side, see PathTo.

CONTENTS

  • EXAMPLES
    • Converting to and from JSON and YAML
    • Plain text representation
    • Basic URI and path generation
    • Dynamic partial template expansion
  • INTEGRATION WITH ROUTES
  • DATA STRUCTURE
    • Attributes
    • Navigation
  • 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 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_py())
{
  "name": "user",
  "uri_template": "http://example.com/users/{user_id}{.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{.format}",
      "params": ["user_id"],
      "optional_params": ["format"],
      "options": ["GET"]
    },
    {
      "name": "user_articles",
      "rel": "articles",
      "uri_template": "http://example.com/users/{user_id}/articles{.format}",
      "params": ["user_id"],
      "optional_params": ["format"],
      "options": ["GET", "POST"]
    }
  ]
}

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

Plain text representation

ResourceTemplate and ResourceTemplates objects print like this:

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

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(actual_params)
"http://example.com/users/dojo.json"
>>> users.path_for(actual_params)
"/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.

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 or set of resources:

>>> 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

INTEGRATION WITH ROUTES

The described_routes.routes module provides integration with Routes, the routing component of Pylons and some other web frameworks.

The make_resource_templates``function will create a ``ResourceTemplates object from a Routes Mapper.

DescribedRoutesMiddleware is a wsgi middleware component that serves ResourceTemplates and ResourceTemplate metadata and decorates regular resources with the link headers that facilitate resource discovery.

DescribedRoutesMiddleware should be placed in the wsgi middleware stack between the RoutesMiddleWare component and the main application. In a Pylons app, the relevant section of config/middleware.py should look something like this:

...
app = PylonsApp()
app = DescribedRoutesMiddleware(app, config['routes.map'])
app = RoutesMiddleware(app, config['routes.map'])
...

By default, ResourceTemplates and ResourceTemplate data will be served at /described_routes; this can be overridden with the path parameter. Assuming the default path is retained, data describing the whole application will be served at /described_routes; data describing a resource corresponding to a ResourceTemplate named 'foo' will be served at /described_routes/foo. In both cases, routing parameters may be supplied, resulting in partially expanded templates, e.g. at /described_routes?format=json.

Data will be served in json format if the path has a .json extension, if the Accept header includes 'application/json' or if there is no Accept header at all. Otherwise the tabular plain text format is served.

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 methods support navigation by name or by rel respectively:

1) ResourceTemplates.all_by_name(): 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.

AUTHOR AND CONTACT INFORMATION

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