Aaronontheweb

Hacking .NET and Startups

Consuming REST in .NET

I gave a talk at Code Camp Los Angeles a couple of weekends ago on how to consume REST APIs in .NET – the emphasis was really on understanding RESTful principles and on the OAuth workflows + implementing them in Windows Phone 7.

It was meant to be a 100-200 level introduction to the REST in .NET – if you’ve implemented OAuth before in .NET then this is old news for you :p

Enjoy!

If you enjoyed this post, make sure you subscribe to my RSS feed!



How to Query a User's del.icio.us Feed with RestSharp

June 14, 2010 12:26 by Aaronontheweb in .NET, Del.icio.us // Tags: , , , , , // Comments (2)

I've been meaning to give RestSharp a go since I first started using Hammock in my startup project's codebase, just because I had heard some good things about RestSharp's auto-parsing capabilities.

This weekend I cobbled together a small example using del.icio.us' RSS feeds (not to be confused with its draconian REST API) for users and RestSharp performed magnificently, although its POCO -> XML Element mapping process requires a lot of experimentation before you get it just right.

Here's an example RSS feed for my personal del.icio.us account:

<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://web.resource.org/cc/">
  <channel>
    <title>Delicious/Aaronontheweb</title>
    <link>http://delicious.com/Aaronontheweb</link>
    <description>bookmarks posted by Aaronontheweb</description>
    <atom:link rel="self" type="application/rss+xml" href="http://feeds.delicious.com/v2/rss/Aaronontheweb?count=2"/>
    <item>
      <title>Windows Presentation Foundation (WPF) Dialog Boxes Overview</title>
      <pubDate>Fri, 04 Jun 2010 23:48:12 +0000</pubDate>
      <guid isPermaLink="false">[REMOVED]</guid>
      <link>http://msdn.microsoft.com/en-us/library/aa969773.aspx</link>
      <dc:creator><![CDATA[Aaronontheweb]]></dc:creator>
      <comments>[REMOVED]</comments>
      <wfw:commentRss>[REMOVED]</wfw:commentRss>
      <source url="http://feeds.delicious.com/v2/rss/Aaronontheweb">Aaronontheweb's bookmarks</source>
      <description>How to use dialog boxes in WPF (for WPF noobs like myself.)</description>
      <category domain="http://delicious.com/Aaronontheweb/">.net</category>
      <category domain="http://delicious.com/Aaronontheweb/">wpf</category>
      <category domain="http://delicious.com/Aaronontheweb/">dialogs</category>
      <category domain="http://delicious.com/Aaronontheweb/">tutorial</category>
      <category domain="http://delicious.com/Aaronontheweb/">nullable</category>
      <category domain="http://delicious.com/Aaronontheweb/">c#</category>
    </item>
    <item>
      <title>Developer's Guide: Data API Protocol - YouTube APIs and Tools - Google Code</title>
      <pubDate>Mon, 31 May 2010 22:43:47 +0000</pubDate>
      <guid isPermaLink="false">[REMOVED]</guid>
      <link>[REMOVED]</link>
      <dc:creator><![CDATA[Aaronontheweb]]></dc:creator>
      <comments>[REMOVED]</comments>
      <wfw:commentRss>[REMOVED]</wfw:commentRss>
      <source url="http://feeds.delicious.com/v2/rss/Aaronontheweb">Aaronontheweb's bookmarks</source>
      <description>Finally figured it out - how to sign all requests with my API key using a querystring. So simple, yet so difficult.</description>
      <category domain="http://delicious.com/Aaronontheweb/">youtube</category>
      <category domain="http://delicious.com/Aaronontheweb/">API</category>
      <category domain="http://delicious.com/Aaronontheweb/">key</category>
      <category domain="http://delicious.com/Aaronontheweb/">Google</category>
      <category domain="http://delicious.com/Aaronontheweb/">gdata</category>
    </item>
  </channel>
</rss>

The best way to utilize RestSharp to parse any sort of API response, whether it's custom REST XML, JSON, Atom, or RSS, is to first take a look at the raw response format and then to try to model a set of Data Transfer Objects (DTOs) which contain the response format elements you want to actually use in your application. Your DTOs just need to be simple POCO objects for this to work, but there are a set of POCO-XML Element matching rules you need to observe if you're using RestSharp's default deserializer - you can read them here.

Here are the classes that I modeled for this RSS format:

public class RssFeed
{
    public string Version { get; set; }
    public RssChannel Channel { get;set; }
}

public class RssChannel
{
    public string Title { get; set; }
    public string Description { get; set; }
    public string Link { get; set; }
    public RssItems Item { get; set; }
}

public class RssItems : List<item>{}

public class item
{
    public string Title { get; set; }
    public string Description { get; set; }
    public string Link { get; set; }
    public string Author { get; set; }
    public string Comments { get; set; }
    public string PubDate { get; set; }
}

This diagram explains how these DTO classes map to the del.icio.us RSS format:

del.icio.us restsharp POCO class to XML document mapping

ProTip: Handling Lists of XML Elements with POCO Classes

One thing that's a bit tricky is handling lists of XML elements, such as the <item> elements in this case. In order for RestSharp to deserialize them, you need create a List<T> object where the name of class T matches the name of the listed element, which is why my class name is item in this case.

Once you have your POCO classes in order, then you need to actually make requests against the del.icio.us feed for a particular user. Here's my code for doing that:

public class DeliciousRequest
{
    public const string DeliciousFeedBase = @"http://feeds.delicious.com/v2/rss/";

    private RestSharp.RestClient _client;

    public DeliciousRequest()
    {
        this._client = new RestClient
                          {
                              BaseUrl = DeliciousFeedBase
                          };
    }

    public RssFeed GetBookMarksForUser(string username)
    {
        var request = new RestRequest {RequestFormat = DataFormat.Xml, Resource = username};
        var response = this._client.Execute<RssFeed>(request);
        return response.Data;
    }

}

All RSS feeds for del.icio.us users can be found using http://feeds.delicious.com/v2/rss/{USERNAME}, therefore you can understand why the RestClient's BaseURL and the RestRequest's Resource arguments are defined as they are. Once you have your RestRequest defined, you simply call the client's Execute<T> method where T is the type of your POCO DTO class.

And that's it - RestSharp is easy, and I look forward to creating some more examples with it down the road.

More RestSharp Examples:

If you enjoyed this post, make sure you subscribe to my RSS feed!



Discussion: How to Use RestSharp / Hammock to Automatically Parse the YouTube Response Format into POCO Objects

June 8, 2010 17:35 by Aaronontheweb in .NET, YouTube // Tags: , , , , , // Comments (3)

If you've been following me on Twitter over the past couple of weeks, you might have noticed that I've been a little frustrated with the YouTube GData API lately. Simply put: XML makes me sad. Since that frustrated Tweet I've developed a solution using LINQ-to-XML and a bunch of hard-coded namespaces which isn't how I would prefer to do it.

I would much rather use the built in object deserialization capabilities in RestSharp or HammockREST. I'll be honest - I do not have a damn clue how to use Hammock's built-in deserialization capabilities. I tried tinkering with it on my own to no avail, and there's not much documentation to speak of.

RestSharp has some more detailed documentation on its deserialization capabilities, but it doesn't answer some lingering questions I have. So without further aideu, I'd like to solicit the opinion of the developer community.

<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/" xmlns:openSearch="http://a9.com/-/spec/opensearch/1.1/" xmlns:gd="http://schemas.google.com/g/2005" xmlns:yt="http://gdata.youtube.com/schemas/2007" gd:etag="W/&quot;DkMMRn0zeSp7ImA9WxFWE0k.&quot;">
  <id>tag:youtube.com,2008:user:smartdraw:uploads</id>
  <updated>2010-05-31T22:21:27.381Z</updated>
  <category scheme="http://schemas.google.com/g/2005#kind" term="http://gdata.youtube.com/schemas/2007#video" />
  <title>Uploads by smartdraw</title>
  <logo>http://www.youtube.com/img/pic_youtubelogo_123x63.gif</logo>
  <link rel="related" type="application/atom+xml" href="http://gdata.youtube.com/feeds/api/users/smartdraw?v=2" />
  <link rel="alternate" type="text/html" href="http://www.youtube.com/profile_videos?user=smartdraw" />
  <link rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml" href="http://gdata.youtube.com/feeds/api/users/smartdraw/uploads?v=2" />
  <link rel="http://schemas.google.com/g/2005#batch" type="application/atom+xml" href="http://gdata.youtube.com/feeds/api/users/smartdraw/uploads/batch?v=2" />
  <link rel="self" type="application/atom+xml" href="http://gdata.youtube.com/feeds/api/users/smartdraw/uploads?start-index=1&amp;max-results=25&amp;v=2" />
  <link rel="service" type="application/atomsvc+xml" href="http://gdata.youtube.com/feeds/api/users/smartdraw/uploads?alt=atom-service&amp;v=2" />
  <link rel="next" type="application/atom+xml" href="http://gdata.youtube.com/feeds/api/users/smartdraw/uploads?start-index=26&amp;max-results=25&amp;v=2" />
  <author>
    <name>smartdraw</name>
    <uri>http://gdata.youtube.com/feeds/api/users/smartdraw</uri>
  </author>
  <generator version="2.0" uri="http://gdata.youtube.com/">YouTube data API</generator>
  <openSearch:totalResults>30</openSearch:totalResults>
  <openSearch:startIndex>1</openSearch:startIndex>
  <openSearch:itemsPerPage>25</openSearch:itemsPerPage>
  <entry gd:etag="W/&quot;CEIHQn47eCp7ImA9WxFWE0k.&quot;">
    <id>tag:youtube.com,2008:video:NJPrllhYZrg</id>
    <published>2010-02-10T23:27:38.000Z</published>
    <updated>2010-05-31T21:48:53.000Z</updated>
    <category scheme="http://schemas.google.com/g/2005#kind" term="http://gdata.youtube.com/schemas/2007#video" />
    <category scheme="http://gdata.youtube.com/schemas/2007/categories.cat" term="People" label="People &amp; Blogs" />
    <category scheme="http://gdata.youtube.com/schemas/2007/keywords.cat" term="SmartDraw" />
    <category scheme="http://gdata.youtube.com/schemas/2007/keywords.cat" term="flowcharts" />
    <category scheme="http://gdata.youtube.com/schemas/2007/keywords.cat" term="visuals" />
    <category scheme="http://gdata.youtube.com/schemas/2007/keywords.cat" term="communicate" />
    <category scheme="http://gdata.youtube.com/schemas/2007/keywords.cat" term="visually" />
    <category scheme="http://gdata.youtube.com/schemas/2007/keywords.cat" term="communication" />
    <category scheme="http://gdata.youtube.com/schemas/2007/keywords.cat" term="powerpoint" />
    <category scheme="http://gdata.youtube.com/schemas/2007/keywords.cat" term="presentations" />
    <category scheme="http://gdata.youtube.com/schemas/2007/keywords.cat" term="mind" />
    <category scheme="http://gdata.youtube.com/schemas/2007/keywords.cat" term="maps" />
    <category scheme="http://gdata.youtube.com/schemas/2007/keywords.cat" term="software" />
    <category scheme="http://gdata.youtube.com/schemas/2007/keywords.cat" term="Business" />
    <category scheme="http://gdata.youtube.com/schemas/2007/keywords.cat" term="graphics" />
    <category scheme="http://gdata.youtube.com/schemas/2007/keywords.cat" term="strategic" />
    <category scheme="http://gdata.youtube.com/schemas/2007/keywords.cat" term="planning" />
    <category scheme="http://gdata.youtube.com/schemas/2007/keywords.cat" term="solutions" />
    <category scheme="http://gdata.youtube.com/schemas/2007/keywords.cat" term="tools" />
    <title>SmartDraw 2010 Guided Tour</title>
    <content type="application/x-shockwave-flash" src="http://www.youtube.com/v/NJPrllhYZrg?f=user_uploads&amp;d=AWaEdOkfU7AZas-hLyE9s8EO88HsQjpE1a8d1GxQnGDm&amp;app=youtube_gdata" />
    <link rel="alternate" type="text/html" href="http://www.youtube.com/watch?v=NJPrllhYZrg&amp;feature=youtube_gdata" />
    <link rel="http://gdata.youtube.com/schemas/2007#video.responses" type="application/atom+xml" href="http://gdata.youtube.com/feeds/api/videos/NJPrllhYZrg/responses?v=2" />
    <link rel="http://gdata.youtube.com/schemas/2007#video.ratings" type="application/atom+xml" href="http://gdata.youtube.com/feeds/api/videos/NJPrllhYZrg/ratings?v=2" />
    <link rel="http://gdata.youtube.com/schemas/2007#video.complaints" type="application/atom+xml" href="http://gdata.youtube.com/feeds/api/videos/NJPrllhYZrg/complaints?v=2" />
    <link rel="http://gdata.youtube.com/schemas/2007#video.related" type="application/atom+xml" href="http://gdata.youtube.com/feeds/api/videos/NJPrllhYZrg/related?v=2" />
    <link rel="http://gdata.youtube.com/schemas/2007#mobile" type="text/html" href="http://m.youtube.com/details?v=NJPrllhYZrg" />
    <link rel="self" type="application/atom+xml" href="http://gdata.youtube.com/feeds/api/users/smartdraw/uploads/NJPrllhYZrg?v=2" />
    <author>
      <name>smartdraw</name>
      <uri>http://gdata.youtube.com/feeds/api/users/smartdraw</uri>
    </author>
    <yt:accessControl action="comment" permission="allowed" />
    <yt:accessControl action="commentVote" permission="allowed" />
    <yt:accessControl action="videoRespond" permission="moderated" />
    <yt:accessControl action="rate" permission="allowed" />
    <yt:accessControl action="embed" permission="allowed" />
    <yt:accessControl action="syndicate" permission="allowed" />
    <gd:comments>
      <gd:feedLink href="http://gdata.youtube.com/feeds/api/videos/NJPrllhYZrg/comments?v=2" countHint="0" />
    </gd:comments>
    <media:group>
      <media:credit role="uploader" scheme="urn:youtube">smartdraw</media:credit>
      <media:description type="plain">Explains the features of SmartDraw, the software that allows you produce any visual, whether it's a flowchart or a floor plan, in a matter of minutes.
Download a free trial of SmartDraw here: http://www.smartdraw.com/downloads/?id=343742</media:description>
      <media:keywords>SmartDraw, flowcharts, visuals, communicate, visually, communication, powerpoint, presentations, mind, maps, software, Business, graphics, strategic, planning, solutions, tools</media:keywords>
      <media:player url="http://www.youtube.com/watch?v=NJPrllhYZrg&amp;feature=youtube_gdata" />
      <media:thumbnail url="http://i.ytimg.com/vi/NJPrllhYZrg/default.jpg" height="90" width="120" time="00:03:21" />
      <media:thumbnail url="http://i.ytimg.com/vi/NJPrllhYZrg/2.jpg" height="90" width="120" time="00:03:21" />
      <media:thumbnail url="http://i.ytimg.com/vi/NJPrllhYZrg/1.jpg" height="90" width="120" time="00:01:40.500" />
      <media:thumbnail url="http://i.ytimg.com/vi/NJPrllhYZrg/3.jpg" height="90" width="120" time="00:05:01.500" />
      <media:thumbnail url="http://i.ytimg.com/vi/NJPrllhYZrg/hqdefault.jpg" height="360" width="480" />
      <media:title type="plain">SmartDraw 2010 Guided Tour</media:title>
      <yt:duration seconds="402" />
      <yt:uploaded>2010-02-10T23:27:38.000Z</yt:uploaded>
      <yt:videoid>NJPrllhYZrg</yt:videoid>
    </media:group>
    <gd:rating average="4.4444447" max="5" min="1" numRaters="9" rel="http://schemas.google.com/g/2005#overall" />
    <yt:statistics favoriteCount="9" viewCount="16206" />
    <yt:rating numDislikes="1" numLikes="8" />
  </entry>
</feed>

Now, here are use cases for how I might want to use this format:

  1. The GData API will only serve a maximum of 50 entries at any given time - one way to paginate through all of the entries in one go is to parse the link rel="next" field and query that URL until the field no longer exists. Is there a way you can use a POCO class in Hammock or RestSharp to automatically grab this field between queries against the API?
  2. Imagine you create a POCO class which contains the YouTube video ID, the author's username, the number of comments on the video, the keywords for the video, the number of views, and the number of the number of favorites. How would you structure this class such that RestSharp or HammockREST can automatically parse it from an ATOM response format like the one above? Bear in mind that these fields come from four of the five different XML namespaces (atom, Media RSS [media], GData [gd], and YouTube [yt]) used in this response format.

If you enjoyed this post, make sure you subscribe to my RSS feed!



Search

About

My name is Aaron, I'm an entrepreneur and a .NET developer who develops web, cloud, and mobile applications.

I left Microsoft recently to start my own company, MarkedUp - we provide analytics for desktop developers, focusing initially on Windows 8 developers.

You can find me on Twitter or on Github!

Recent Comments

Comment RSS

Sign in