Ahora
An alternative to ActiveResource for consuming Java-ish XML HTTP Resources easily. Ahora glues together two amazing Ruby libraries: Faraday and Nibbler.
If your project meets any of the following requirements, you might be interested.
- You want to consume an external XML resource.
- You want to map camelCase names to underscore_case.
- You want to parse Date, Time and boolean values automatically.
- You want to be a good citizen on the web and support caching (e.g. If-Modified-Since).
- You want to use fragment caching on the front-end. So it should generate a cache-key.
- You might have a recently cached fragment, so XML collections should be lazy loaded.
This is a big list, you might not need all these requirements. At least the code can act as an example on how to approach one of these problems.
Example
Let's say you want to display to following XML on a page in a Rails project
<?xml version="1.0"?>
<userPosts type="array">
<userPost>
<hidden>false</hidden>
<objectId>1</objectId>
<userObjectId>1</userObjectId>
<user>
<firstName>John</firstName>
<lastName>Doe</lastName>
</user>
<body>How is everybody today?</body>
<createdAt>2011-10-26T17:01:52+02:00</createdAt>
<replies type="array">
<userPost>
<objectId>2</objectId>
<parentObjectId>1</parentObjectId>
<userObjectId>2</userObjectId>
<user>
<firstName>Mike</firstName>
<lastName>Smith</lastName>
</user>
<body>I am fine, thanks for asking.</body>
<createdAt>2011-10-27T9:00:00+02:00</createdAt>
</userPost>
<userPost>
<objectId>3</objectId>
<parentObjectId>1</parentObjectId>
<userObjectId>1</userObjectId>
<user>
<firstName>John</firstName>
<lastName>Doe</lastName>
</user>
<body>You are more than welcome.</body>
<createdAt>2011-10-27T9:00:00+02:00</createdAt>
</userPost>
</replies>
</userPost>
<userPost>
<hidden>true</hidden>
</userPost>
</userPosts>
You start by defining a class with methods to retrieve the resource and another class to act as a mapper.
class Post < Ahora::Representation
objectid :id, :user_id, :parent_id
date :created_at
element :body
element 'user', :with => Ahora::Representation do
string :first_name, :last_name
end
boolean :hidden
elements 'replies/userPost' => :replies, :with => Post
end
class PostResource
include Ahora::Resource
def all
collection Post, get("/api/posts.xml")
end
private
def host
'http://test.net'
end
def extend_middleware(builder)
builder.use Ahora::Middleware::LastModifiedCaching, Rails.cache
end
end
Now you can define a controller as usual.
class PostsController < ApplicationController::Base
def index
@posts = PostResource.new.all
end
end
And a view template
<% cache @posts, 'index' %>
<%= render(:partial => @posts) %>
<% end >
And that's all there is. The XML response will be cached, so it saves a bandwith. The XML response will only be parsed if there is no existing HTML fragment cache. All cache will be invalidated when the request to posts.xml returns a new body instead of a 304 Not Modified.