Introducing a Ruby OData Client Library

OData_logo_MS_small Ever since the ADO.NET team started development on Astoria (pre-release), I have loved the concept.  Since its release (it was called ADO.NET Data Services and is now WCF Data Services), I’ve used it a ton (you may remember the example from this post).  Back at MIX10, Microsoft announced a commitment to the Open Data Protocol (OData).  WCF Data Services enables you to create services that use OData to expose and consume data, both with .NET 4 and .NET 3.5 SP1.  OData services are very powerful and there are quite a few live producers such as Netflix and Nerd Dinner.

OData is so powerful because it’s REST based and you can access the services from just about everywhere, including just a simple URL.  For example, using the Netflix OData service to access the best movie ever made by title: http://odata.netflix.com/Catalog/Titles?$filter=Name eq ‘Office Space’.  Pretty simple.  Of course accessing things solely based on URLs in code isn’t the best, and hence the reason for my post.

Client Libraries

When using OData, it’s convenient to utilize an SDK to access the services.  For example, in Silverlight you can access OData services using LINQ.  There’s also a fantastic AJAX Library (which I used in a previous post).  There are SDKs for PHP, Objective-C, and many others, but there was one missing that I wanted to use… Ruby.  I am assuming this comes as no surprise given my new found love for Ruby.


Introducing ruby_odata

I’ve been messing around with Ruby enough to start working on my first Ruby open-source project.  It’s always good to contribute to the open-source community.  While I’m not a seasoned Ruby developer, I figure this is a good project to start on.  Now I can code stuff in Ruby and consume WCF services I have written in the past and will continue to write in the future (that is until there is “OData on Rails,” perhaps an idea for a new project?).

The source code, like all good Ruby code, is hosted on GitHub.  The README will give you a good idea of how to use the library.  Currently (as of 06/12/2010) there are limitations, such as not being able to batch changes (like multiple Adds), but no worries, I’m working on adding them (actually, I cut three releases today, adding extra querying abilities).  That said, it is functional enough to use for most operations right now.  Once it’s been better tested in the real world and I’ve been able to incorporate most if not all of the OData functionality, I will be versioning more responsibly.  Right now, because I’m adding functionality quickly and I want others to be able to use it, you’ll be seeing lots of updates so the version number will be a bit jumpy for a while.

The Genesis of ruby_odata

I started writing ruby_odata in order to interface with my database via services so I could do testing in Ruby and create objects from within the tests that I could use in my ASP.NET MVC application.  I wrote about BDD testing in an earlier post where I fixed the speed of running the tests using Cucumber with Mechanize.  Another area missing in .NET is the ability to automatically generate objects to test against like you can with Ian White’s Pickle.   Pickle interacts nicely with factories and your database to create objects for tests.  For example, a step like: Given a user exists with name: "Damien" will automatically create a new user in the test database.  This works dandy in the Ruby world (with ActiveRecord for example), but against something like Entity Framework, not so much.  With ruby_odata however, this is something that could work in a similar way. (Yet another idea for a project, a Pickle adapter that utilizes ruby_odata.  Man, so many ideas, so little time.)

Usage Overview

The library is pretty straightforward to use.  At the heart is the OData::Service.  This is the root object that drives all of your operations against the services.   Once you instantiate the OData::Service, dynamic methods based on the OData service’s collections are available to call.  For example, using the Netflix OData service, we can see there is a collection called “Titles.”  Within ruby_odata, the OData::Service will respond to a “Titles” method:

svc = OData::Service.new "http://odata.netflix.com/Catalog/"
puts "Responds to Titles? #{svc.respond_to? :Titles}" # => Responds to Titles? true


So, just by looking at the collections on the main service page, or metadata page, you can see what you can query.  Here’s an example of querying for a movie (like we did earlier with a straight up URL):

svc.Titles.filter("Name eq 'Office Space'")
movie = svc.execute

# Now we can access properties of the Title (defined in the service metadata)

puts "Average Rating: #{movie.AverageRating}"
puts "Release Year: #{movie.ReleaseYear}"
puts "URL: #{movie.Url}"

# => Average Rating: 4.2
# => Release Year: 1999
# => URL: http://www.netflix.com/Movie/Office_Space/20358351

Pretty cool, huh?

The Basics

There is a simple pattern for using the library.  For queries, you call a collection on the service (like you saw with Titles in the Netflix example above), and that returns an OData::QueryBuilder object to you in which you can fluently add options like filter or expand.  If you use multiple calls to filter, it will perform an “AND” query against the service, and multiple expand calls will yield multiple items being expanded.  You can also mix the calls, like .filter(…).expand(…).  Once you are done building a query, you call the execute method on the service.  The result of the execute is either a single entity or a collection of the entities based on your query.

In order to add, update, or delete, you need to call the appropriate method on the OData::Service.  To add, you would use the dynamic method AddTo<Collection Name>, where the <Collection Name> is the name of the collection on the service (as defined by the metadata).  To update, you would use update_object, passing in the updated version of the object.  Finally, to delete, you would use delete_object, passing the object to delete.  Once you do one of these operations, you need to persist the change using the save_changes method on the OData::Service.  Currently, you need to call save_changes after each operation in order to persist the data.  In the future you will be able to batch operations instead of persisting them one at a time.

More Examples

For more examples, download the source code from GitHub and setup the testing environment (instructions for setting up the test environment are located in the README).  When you setup the test environment, you can follow along with the samples as shown in the README.  There are examples for all the CRUD operations.

Conclusion

There you have it, an OData library for Ruby.  I am very excited by the potential of OData, and having the ability to consume the services easily within Ruby is extremely useful.  I hope you find the library helpful.  The current version is a bit of a work in progress since everything isn’t fully supported yet, but I will continue to work on the project.  You can get involved by checking out the resources for the project:

If you just want to start using it without the source code, you can install ruby_odata as a gem from RubyGems.org.

I am a software architect with over 13 years of experience. I simply love coding! I have a driving passion for computers and software development, and a thirst for knowledge that just cannot be quenched. I'm happy to share what I knows in my quest to learn as much as possible. I focus most of my time on web development using Ruby on Rails and ASP.NET MVC.