Manifesto and roadmaps for described_routes and path-to

Introduction

Clients of RESTful web applications typically use prior knowledge of the target application’s structure to generate URIs.  This approach is often very convenient, but much of this URI generation is hard-coded, and (worse) spread across client code. This introduces a high degree of coupling and makes clients unnecessarily vulnerable to server-side change.

Steps to improve this situation:

  1. In clients, centralise the generation of URIs and make the process driven by configuration data
  2. Have servers publish the required configuration data – i.e. application metadata – in a readily understood format

path-to provides the means for client applications to model web applications in terms of logical structure and URI mappings, and to interact with them through dynamically-generated application-specific APIs.  described_routes supports an application metadata structure (published in JSON, YAML and XML formats) that can be consumed by path-to, and (helpfully) generates it automatically online or offline from the routes configured for a Rails-based application.

The two libraries can be used separately or together – an JavaScript client is under independent development for example.  Moreover, the underlying metadata format is framework-neutral; we have been careful not to “leak” Rails concepts into it.

1. described_routes

“Framework-neutral metadata describing Rails routes in JSON, YAML, XML and plain text formats”

The project has three main elements:

  1. Rake tasks that produce representations of a Rails application’s entire structure offline
  2. A simple controller that supports online access to these representations, adding the ability to pick out structures rooted on specified named routes
  3. The ResourceTemplate class and the formats that it generates and parses.    This is completely independent of Rails, in terms of both code dependencies and data structure.

The ResourceTemplate format describes a hierarchical organisation of web resources together with their:

  • logical names (their route names in the Rails case, e.g. “user_articles”)
  • logical parent-child relationships (e.g. “edit”, for a resource’s edit form)
  • URI Templates and the names of the parameters required to populate them
  • supported HTTP options (GET, PUT, POST, DELETE)

These metadata representations are derived automatically from the routes description that is conventionally coded in config/routes.rb.  See the appendix at the end of this article for examples.

Current status:

  • Working, published (as a github repository and as an installable rubygem on RubyForge)
  • To my knowledge it has been tested only by myself (on some of the examples given in the boilerplate config/routes.rb)

Still outstanding:

  • Parsing of the XML representation (and tests of round trips with the JSON and YAML formats)
  • The offline rake tasks are unaware of the application’s base URI and therefore can only produce templates to paths.  Find a way to get the base URI for a Rails environment offline (I’m not even sure this is possible), or allow one to be provided as a parameter. UPDATE (May 6th): added parameter “BASE=http://…” to rake tasks

Possible future work:

  • Solicit real-world examples for testing, unusual ones especially!  All I would need are config/routes.rb files and willingness to review/discuss the resulting representations
  • Break out the ResourceTemplate class into its own gem
  • Generate ResourceTemplate representations for specific resource instances (where the URI templates of child resources are partially populated with the root instance’s URI parameters), facilitating a more dynamic (and arguably more RESTful) interaction style
  • Generate URI Template mappings for query parameters
  • Implementations for Ruby web frameworks other than Rails.  Where frameworks lack the routing metadata of Rails this will entail work on the part of the application developer however.
  • Non-Ruby implementations UPDATE (June 2nd) basic Python ports done
  • Investigate alternatives to URI Templates, make this a pluggable choice
  • Add customisation hooks (@siebertm): UPDATE (May 6th): done

2. path-to

“Model web apps easily and access them via nice app-specific Ruby APIs”

path-to predates described_routes, and with a modest level of coding effort it can be used without it (see this early example). From the beginning I had however hoped to find a suitable format already in existence but with no real success so far!  With described_routes, path-to provides a Ruby client API to a Rails application for almost no effort, as shown in this more recent example.

Current status:

Still outstanding:

  • Demonstrations of access to well known web APIs – realistic examples with authentication etc.  UPDATE (May 8th): added Delicious example.

Possible future work:

  • positional parameters, allowing (for example) users['dojo'] as well as users['user_id' => 'dojo'] UDPDATE (May 12th): done
  • Support other metadata representations as they are brought to my attention (are there any good ones out there?)
  • Port to Python; demonstrate easy Python/Rails interop UPDATE (June 2nd) basic Python ports done

Appendix – examples

3 thoughts on “Manifesto and roadmaps for described_routes and path-to

  1. I have been looking at the path_to and described routes gem pair. They both work well for me Rails 2.2.2 and jruby 1.1.5. I have a problem though.

    Let say I have an app that has an api like this:

    instructions instructions GET, POST http://localhost:7010/instructions
    {instruction_id} instruction GET, PUT, DELETE http://localhost:7010/instructions/{instruction_id}

    I can do app.instructions['1'].get

    I also get given a uri string which must be got. I can use HTTParty to get this.

    uri = ‘http://localhost:7010/instructions/2′

    Is there a way to test whether this uri is compatible with the described routes of the app?

    I would like to do something like this

    app.check(uri, :method => ‘get’) do |api|
    api.get
    end

    but if there is another way of just testing the uri against the described routes I’d be happy to find out.

  2. Hi Guy,

    Any URI generated by described_routes or path-to should have any parameters escaped so that a match to the original template is assured. I don’t personally have applications that take URIs from other sources so this hadn’t occurred to me as a possible requirement.

    The underlying URI Template library (Addressable, in the case of the Ruby implementation) may offer URI parsing. When I get a moment I’ll check.

    Mike

  3. Yes it turns out you can easily test URIs with Addressable:

    Addressable::Template.new(rt.uri_template).match(input_uri) # rt has a stored absolute uri_template
    or
    Addressable::Template.new(rt.uri_template(base)).match(input_uri) # rt has only relative path_template, not stored uri_template

    will return a parameter hash if the URI matches the template, nil otherwise.

Comments are closed.