RailsConf Europe: Hydra

Posted by Nick Sieger Sat, 06 Oct 2007 12:04:00 GMT

Hydra

On September 19, Craig and I presented our talk at RailsConf, which appears to have been well received. It went off mostly without a hitch, if it wasn’t for a couple of hiccups in the demos. I apparently didn’t practice them enough, because a couple of critical steps were either missed or I did them out of order and confused myself. But that’s ok, because I’m releasing the demo steps, source and slides here so you can try them out for yourself.

So, download the zip and follow along. The contents look like this:

1-active-resource-basics.txt
2-make-resourceful.txt
3-atom-roller.txt
4-service-chatter.txt
RailsConfEurope-Hydra.pdf
demo/
demo-baked/

The demo steps are in the text files; I’d recommend going in the order specified. It turns out the third isn’t really a demo but more of a code review, because it also requires you to have Roller set up and I’m not going into those details for now. If you want to just run the demos, skip to demo-baked, the finished product.

For those of you who didn’t see the talk, here’s the basic message.

Look at your basic MVC Rails app.

Single app

Why not consider spliting it into two? ActiveResource allows you to access a RESTful resource in your Rails application like it was just another model.

Double app

This might seem like overkill for a simple application, but what if you had an e-commerce application domain like this?

E-Commerce app

Splitting up your code into separate Rails applications encourages encapsulation, reduces potential coupling, and gives you more flexible deployment options. Basing interactions upon REST and HTTP means that you can more easily mash up data or create caching strategies, given proper usage of ETags/Last-Modified and/or cache-control headers. The great thing is that existing HTTP reverse proxies can be used without having to mix the caching code in with your application code.

In the application we’re building, we have a number components that are not Rails-based. To expose them to our environment, we’ve taken the strategy of exposing a simple REST web service for the component, and then it can be consumed by the other applications using ActiveResource. The REST web service can either be implemented in the component’s native language/technology, or in some cases we’ve written a wrapper service in Rails since Rails makes it so easy to build REST interfaces. In that case, Rails is pure integration -- RESTful glue.

The idiom that makes this all possible is the uniform interface. In HTTP, this means addressability (each resource gets a unique URI) coupled with the HTTP method verbs HEAD, GET, POST, PUT, and DELETE. Inside your Rails applications, it’s the ActiveRecord interface. If you keep your controllers skinny, you can boil the interface down to the following set of methods (in this case, for the prototypical blog post model):

Post.new/Post.create
Post.find
@post.save
@post.update_attributes
@post.errors
@post.destroy

And in fact, this is precisely what ActiveResource provides, and it’s enabled by duck-typing. Walking through the demos illustrates this pretty well, as you’ll basically swap ActiveRecord for ActiveResource with no noticeable difference, all the way down to validation errors in the scaffolded forms (which I was unable to demo in the talk due to the hiccups).

We’ve found that when you’re making RESTful web services, the controllers largely become boilerplate because of the uniform interface. make_resourceful has been a boon in that regard, as the demos also show. There are several plugins that help you DRY up your controllers (other approaches include resources_controller), so you have some choices there.

We mentioned some drawbacks in our experience with ActiveResource, which have largely been addressed for the upcoming Rails 2.0 release.

Finally, we noted that deployment could be a pain with so many Rails applications to keep running. To that end, we are leveraging JRuby and Glassfish to make this a non-issue, as we simply WAR up our Rails applications with warbler and let Glassfish take care of the rest. Performance is still an open question, but we plan to roll up our sleeves and make sure this combination really hums.

Enjoy the demos! Feel free to drop me an email if you have any questions or troubles with them.

Tags ,  | 5 comments

Comments

  1. Avatar Comedian said about 6 hours later:

    “the HTTP method verbs HEAD, GET, POST, PUT, and DELETE.”

    You’re HEADing me.

  2. Avatar Assaf said about 8 hours later:

    “The great thing is that existing HTTP reverse proxies can be used without having to mix the caching code in with your application code.”

    When Cache-Control is private, which it is by default, it means no caching by the proxy, but the application itself can cache the data.

  3. Avatar Nick said about 16 hours later:

    Assaf: Are you saying this approach is not worth mentioning/attempting, or requires application tweaking anyway to change cache control?

  4. Avatar Assaf said 1 day later:

    I depends on what you’re trying to do.

    If every request to the same resource returns the same data, and there are no complex transformations on the client, then the easiest solution is to change the Cache-Control headers in Rails to remove ‘private’, and put a caching proxy between the client and server.

    It saves a lot of load on the server for the few minutes it takes to setup and configure a proxy. I don’t know of many applications like that.

    If you handle client requests differently for the same resource -- say you’re using authentication and some users can see the data but others can’t -- then you need to specify private in Cache-Control, otherwise your proxy will be leaking information to the wrong clients.

    For that, you need caching in the client library, say ActiveResource or something on top of Net::HTTP.

    If your client is doing complex work on the data it receives, then you don’t want to use either cache, but handle ETag/Last-Modified directly.

    For example, if the client reads a 10MB document only to calculate and store ‘total orders for the day’, then using a cache would reduce the load on the server, but you’ll still have to process 10MB of data each time you read it from the cache.

    On the other hand, you can store the result along with the ETag/Last-Modified headers and use conditional GET to not do any processing unless the data changed.

  5. Avatar Tim Connor said 9 days later:

    I’ll have to check out those plug-ins, If you like the simplicty of being able to easily edit your controller, but still keep it DRY, you can use an abstract controller, though. For instance, I wrote one available at: http://code.google.com/p/restcontroller/ ;)