Entries from January 2009

The Wonderful World of Web Hooks

I just read through a presentation on web hooks by Jeff Lindsay, and the concept really excited me. They allow developers to build powerful web services with little overhead and a low barrier to entry. Hopefully, over the next year or so, more applications will begin to use hooks to create a more connected and powerful web.

What are Web Hooks?

The best example of web hooks I’ve found is GitHub, a social code hosting service. In each project you create, you can specify a “post-receive hook”, which is just a URL of your choosing. Whenever someone pushes new code to the project, GitHub sends an HTTP POST to this URL, and you can do whatever you want with the data. For instance, say you wanted to send an email to your team, notifying them of the changes. You could write a simple PHP script like this:

  $data = $_POST['payload'];

  $subject = count($data['commits']) . " new commits"
  $body = "New code has been committed to the project: \n";

  foreach($data['commit'] as $commit) {
    $body .= "Commit: " . $commit['id'] . "\n";
    $body .= $commit['message'] . "\n\n";
  }

  mail($recipients, $subject, $body);

Now, if you set the URL of this script as your post-receive hook, whenever someone pushes code, GitHub POSTs the data to the URL, and an email is sent to your team. Not only is this really powerful, but it’s also much more efficient than traditional methods.

Web Hooks = Efficiency

Suppose you wanted to build an app with the same functionality as described above, but without using hooks. You would need to create a script that grabbed your project’s RSS feed, parsed it, and sent an email if there’s new information. This wouldn’t work nearly as well as before. Look at the script above: 8 lines of code. With the added steps of fetching the feed and parsing it, you’re adding considerable complexity to your code, plus you need a way to tell what content is new, so you don’t send out duplicate emails. Not only is this a lot of steps, but you also need to schedule it to run on a consistent basis using a cron job or something similar.

This all means you’re putting a greater load on both your application and on GitHub. Much of the time, when your script is run, it won’t find any new data, wasting both GitHub’s and your resources. With a web hook, your script waits patiently until something happens, and is only run when there’s a reason. It’s also run immediately after the action occurs, i.e. when GitHub receives a commit, it pings your script right away. If you have to poll an RSS feed, you might not know for a while, depending on how often the script is run.

The Future

Where hooks will really succeed, I think, are as lightweight web services, like Jeff’s MailHook, a service that receives emails and POSTs the information to your hook. Jeff took it down, since it was more of a proof-of-concept than anything else, but applications like this are really exciting. I’d definitely recommend looking through Jeff’s presentation (if you haven’t already), as he has some great examples of existing sites that use web hooks, as well as insight into the future of this method of interaction.

The aspect that excites me the most is how easy it is to write a web hook. All you need to have is a cheap PHP host and some basic knowledge about handling POST data, and you’re ready to go. By shortening the learning curve, web hooks make it possible for more people to build on top of existing platforms, leading to a more connected and interesting internet.

Posted on January 8, 2009 Leave a Comment
Tagged with: , , ,

Making Better Use of named_scope

In Ruby on Rails 2.1, a great little feature called named_scope was added that really makes complicated finds a whole lot easier. I’m going to walk through one way you can use scopes to clean up your code, and if you want more information, Ryan Daigle’s post is a good starting point.

The Situation

For a project I’m working on, users can submit reviews, and I needed a way to access a user’s friends’ reviews. At first, I considered adding a method like the following to my User model:

class User < ActiveRecord::Base
  def friends_reviews
    Review.find(:all,
      :joins      => "JOIN friendships ON user_id = #{self.id}",
      :conditions => "friendships.friend_id = reviews.user_id"
    )
  end
end

Named Scopes to the Rescue

While this method would work fine, there are several issues. For one, what if I want to change parameters on the find, like limiting it to 5 entries, or sorting by date? I would have to add parameters to the method, and it would start to get complicated. Instead, I created a scope in my Review model:

class Review < ActiveRecord::Base
  named_scope :by_friends_of, lambda { |user|
    {
      :joins      => "JOIN friendships ON user_id = #{user.id}",
      :conditions => "friendships.friend_id = reviews.user_id"
    }
  }
end

Now, to get the reviews I want, I can call Review.by_friends_of(user) and it will get me reviews by user’s friends. What’s even better, since it’s a scope, I can modify it. For instance, Review.by_friends_of(user).all(:limit => 10, :order => "created_at DESC") will limit it to 10 reviews, sorted by creation date. I can even use other scopes I might have created, like: Review.by_friends_of(user).published.all(:limit => 20), and so on.

Scopes are super useful, and recently I’ve started to use them for just about everything. Definitely try them out, they’ll make your code a lot more efficient and useful.

Posted on January 6, 2009 1 Comment
Tagged with: , , , , , ,