More Fun with C# 4.0 – Dynamic REST Service Calls

This followup post on the C# 4.0 dynamic feature demonstrates taking dynamic JSON further to dynamic or proxyless REST service calls turning dynamic method calls into HTTP requests…

In my last post, I blogged about the upcoming C# 4.0 dynamic feature and using it to work with JSON data in a more natural late-bound manner. I also alluded to where I was heading with the idea – issuing calls to REST services through a dynamic interface.

Specifically, I was thinking of being able to have a dynamic object represent a proxy to a REST service, and having its encapsulated late-binding behavior turn method calls into actual HTTP requests, serializing parameters into URL query string parameters, and finally processing responses (JSON or XML) into a dynamic object for the caller to poke into and extract interesting pieces of data. This post builds on the previous one, so be sure to check that out.

Also, do check out the comments. There was a lot of interesting commentary about how c# and dynamic don’t mix together. It is an interesting debate no doubt, and I thought I should summarize my perspective. I personally tend to think dynamic is just another tool, and when used appropriately it is quite nice. Often times there is a small bit of code where late-binding would help, and its nice to be able to do so in c#, without switching to another dynamic language and losing all static typing in the process, or having to split your code artificially. Instead I envision using and encapsulating late-binding code within an object, and then using that object itself in a strongly-typed, compile-time-bound manner in the rest of the app.

Back to REST services… it is interesting to look at an example, such as Flickr.

Looking at its API documentation page, you can see Flickr offers around 100 or so APIs. Every single API has numerous permutations of parameters (just look at search for example). It would be an fairly big and non-trivial task to create a full-featured toolkit, and keep it up to date as the service evolves. More often than not an app just wants a handful of APIs. What if there was a generic and dynamic REST proxy that could out-of-the-box support typical REST services. That would at least facilitate quick and dirty prototyping even if you do decide later to turn just the APIs you care about into a strongly typed REST client library for the actual implementation. The same pattern repeats itself with other services such as Amazon, Facebook and so on.

Once I had this generic REST client coded up, I could write the following code to work against Flickr:

internal static class FlickrSample {
    private static void WritePhotos(dynamic list) {
        foreach (dynamic photo in list.photos.photo) {
            Console.WriteLine(photo.title);
            Console.WriteLine(String.Format("http://farm{0}.static.flickr.com/{1}/{2}_{3}.jpg",
                                            photo.farm, photo.server, photo.id, photo.secret));
            Console.WriteLine();
        }
    }

    public static void Run() {
        dynamic flickr = new RestClient(AppSettings.Default.FlickrUri, RestClientMode.Json);
        flickr.apiKey = AppSettings.Default.FlickrApiKey;

        Console.WriteLine("Searching photos tagged with 'seattle'...");
        dynamic photosOptions = new JsonObject();
        photosOptions.tags = "seattle";
        photosOptions.per_page = 4;
        dynamic searchResponse = flickr.Photos.Search(photosOptions);
        WritePhotos(searchResponse);

        Console.WriteLine("Searching interesting photos...");
        dynamic interestingList = flickr.Interestingness.GetList();
        WritePhotos(interestingList);
    }
}

I could also use the same exact generic REST client to work against Amazon, which returns XML rather than JSON (but that difference is handled through my library by creating a dynamic layer over System.Xml.Linq):

public static void Run() {
    dynamic amazon = new RestClient(AppSettings.Default.AmazonUri, RestClientMode.Xml);
    amazon.subscriptionID = AppSettings.Default.AmazonSubscriptionID;

    dynamic searchOptions = new JsonObject();
    searchOptions.SearchIndex = "Books";
    searchOptions.Keywords = "Dynamic Programming";

    dynamic bookList = amazon.ItemSearch(searchOptions);

    foreach (dynamic book in bookList.SelectAll("Item")) {
        Console.WriteLine(book.ASIN + " : " + book.ItemAttributes.Title);
    }
}

REST client itself doesn’t know about Flickr or Amazon. It simply takes in the URI handed to it in its constructor, and does a few things:

  • Replace named tokens like apiKey={apiKey} in the URI with properties set on the RestClient object (eg. apiKey in the Flickr sample and subscriptionID in the Amazon sample)
  • Derives the REST operation name from the method call name in the code (Photos.Search, Interestingness.GetList and ItemSearch)
  • Serializes the JSON object passed in containing parameters as query string values
  • Deserializes the response using either the JsonReader for JSON responses or XDocument for XML responses into either a JsonObject or XmlNode (both are dynamic themselves).

You can check out the code and if you have the VS2010 and C# 4.0 CTP, you can run the sample (you’ll need to get your own Flickr API key and Amazon subscription ID and place them in App.config before running them). The interesting places to put a breakpoint to see whats happening are in the GetMember(), SetMember() and Call() implementations of RestClient.

As a side note, I am dabbling a bit with github for source code hosting – the source code for the project is shared in a github repository, where you can browse the code online, follow any future changes, or even fork the code to experiment with your own ideas

http://www.nikhilk.net/CSharp-Dynamic-Programming-REST-Services.aspx

About eagle081183

Passionate, Loyal
This entry was posted in Integration, SOA, Software architecture, Web 2.0 API vs RSS Reader. Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s