We’ve watched described_routes and path-to grow here over the past few weeks. And fun though it has been for me, it must be hard to get a good overview from blog posts triggered by design challenges! So here goes: an attempt at a one-post overview.
In a sentence?
Add described_routes to your Rails application to give it header-based site discovery with ResourceTemplate metadata that enables instant Ruby APIs on the client side with path-to.
And if I’m not using Rails or even Ruby?
There’s library support for ResourceTemplate metadata in Ruby (for the moment it’s included as part of described_routes) and Python (see described_routes-py). There’s a simpler version of path-to available in Python also, namely path-to-py. And there’s nothing Rails-specific or complicated about ResourceTemplates either – strip away the JSON, YAML or XML formatting and they’re not much more than named resources arranged hierarchically with their URI templates and supported HTTP methods as properties – and (so I’m told) can be useful even without path-to.
OK – I’m sold! What do I have to do?
Just follow these simple steps:
- Install
described_routesfor the server - Add build-time integration to the server
- Add basic run-time integration to the server
- Add site discovery to the server
- Install and run
path-to - Profit!
The README files of the two gems tell you all you need to know in detail, but here in one place:
1. Install described_routes for the server
$ sudo gem install described_routes
2. Add build-time integration to the server
This is just a set of Rake tasks that lets you see immediately what the metadata looks like. In your Rakefile:
require 'tasks/described_routes'
Then try it out:
$ rake --tasks described_routes rake described_routes:json # Describe resource structure in JSON format rake described_routes:xml # Describe resource structure in XML format rake described_routes:yaml # Describe resource structure in YAML format rake described_routes:text # Describe resource structure in text (comparable to "rake routes")
Specify the base URI of your app with "BASE=http://..." to see full URIs in the output.
3. Add basic run-time integration to the server
Somewhere in your application include the controller, perhaps in an initializer:
require 'described_routes/rails_controller'
Add the following route in config/routes.rb:
map.resources :described_routes, :controller => "described_routes/rails"
You can now browse to /described_routes(.format) and /described_routes/{controller_name}(.format) and see the data generated at run time.
4. Add site discovery to the server
Site discovery (linking resources to their resource-specific and site-wide metadata) works via link headers (“Link:“) added to the responses served by one or more controllers. This has a double benefit:
i) Resources gain some type information derived from the Rails route name of the resource that may be of value to clients
ii) A path-to client (or any other client interested in the ResourceTemplate metadata) can be initialised from a regular resource URI; prior knowledge of metadata location is not needed.
According to your requirements, add the set_link_header filter to either the controller of your root resource (&/or or other specific controllers) or to ApplicationController in order to benefit all controllers:
require 'described_routes/helpers/described_routes_helper' class MyController < ApplicationController include DescribedRoutes::DescribedRoutesHelper after_filter :set_link_header end
Install and run path-to, …profit!
$ sudo gem install path-to
It is now a one-liner to bootstrap a client application, in this example a test blog with user and article resources:
require "path-to/described_routes"
# bootstrap a path-to client from the test_rails_app provided in described_routes
app = PathTo::DescribedRoutes::Application.discover("http://localhost:3000/")
#=> <PathTo::DescribedRoutes::Application>
# get user 'dojo'
puts app.users['dojo'].get
#=> '<html>...</html>
#get a JSON representation of the recent articles of user 'dojo'
puts app.users['dojo'].articles.recent['format' => 'json'].get
#=> [...]
Profit!
This bit is up to you, but metadata-enhanced web apps and instant client APIs achieved for so little work has to be worth something!
Pingback: Double Shot #505 « A Fresh Cup