Intercepting microformats in rails input

In Input formats and content types in Rails 1.2 I mentioned a project I’ve been working on that will provide a RESTful service interface which accepts its input in a number of formats, including microformatted HTML.

For certain types of data microformats provide a great way to receive input as they don’t require your clients to learn a new schema to send you data. They can take the same semantically rich HTML they’re displaying on their website and POST it to your endpoint. Or they can use a tool like Ryan King’s hcalendar creator to generate some sample input.

But intercepting and interpreting that data isn’t quite so simple as JSON or XML. Those formats have well defined content types that we can use to identify them, and use the parameter parsers I described in my earlier blog entry. Microformats are HTML and so will come with an HTML content type, just like other forms of input.

It would be nice if there were a simple way (short of running them through a full parser) to identify POSTs whose bodies contain microformats, but so far I haven’t come across one. What we can do is to override rails’ default handlers to parse the raw post data and see if it looks like regular form input. If it doesn’t, we can presume it’s meant to be considered to be microformat data and we can do some parsing using the excellent mofo (on which more, later). My code at present is:

microformat_interceptor = Proc.new do |data|
  parsed = CGI.parse(data)

  if parsed.collect { |key, value| key + '=' + value[0] }.first == data
    { :event => HCalendar.find(:text => data) }
  else
    CGIMethods.parse_request_parameters(parsed)
  end
end

Mime::FORM = Mime::Type.lookup("application/x-www-form-urlencoded")
ActionController::Base.param_parsers[Mime::FORM] = microformat_interceptor
ActionController::Base.param_parsers[Mime::HTML] = microformat_interceptor

With that code in environment.rb, a request with hCalendar data in its post body will look to our actions as if it had an HCalendar object in params[:event]. If we extend a few of our event model’s methods, our controller can treat this input just as it would XML or a standard query string.

Obviously this is a work in progress, its output is very simple, and it’s not all that versatile, but so far my tests stand up well, and it makes the code considerably more elegant.

For a little more on microformats and APIs, check out Drew’s “Can Your Website be Your API?” and the REST page on the microformats wiki.

Tags: , , , ,

5 comments

  1. We’re doing something a bit similar. We discovered Why’s great new Hpricot html parser which is fantastic. It allows css type selecting of elements within, which is perfect for microformats. It’s also really fast.

    I’ll try and write a little post about it next week (I’m moving this week). In the mean time, google hpricot. Like all of Why’s libraries it’s slick, fast, different and easy to use.

  2. Glad it’s not just me!

    Yeah, I love hpricot and have been using it as often as possible. Mofo, which I’m using to parse the microformats is actually built on top of it and provides a simple DSL for defining classes to represent microformats. You can find it at http://mofo.rubyforge.org

    What I’m trying to do here is to make the use of the microformats invisible to the controller using the param_parser, but I don’t want all my parameters passed through hpricot/mofo because of the extra overhead that would add to standard web requests, even with the efficiency of hpricot.

  3. […] article builds on some posts on this blog, such as Intercepting Microformats In Rails Input, but offers a bit more context. The timing of the article fits nicely with a post on the […]

  4. Microformatos con Rails…

    …3750″ id=link_5>Mofo – Parse Microformats with Ruby (Snippet)

  5. […] follow the microformat world over at the planet. Therein you may stumble upon blog posts about intercepting microformats in Rails input or versatile RESTful APIs beyond […]