Saturday, August 21, 2010

Using Restsharp to access the iTunes Search API

In Festival Star, when a new band is entered into the system, we automatically search iTunes for the artist to find all of their tracks available to preview in the app. The results are cached in our database and served to the users when requested. This means we access the iTunes API only once per act (unless it's being updated) and we can feed the results to our users quicker. Ideally we'd access the API from within the app, directly, but the chances of that going pete are too high plus Apple request consumers access the API with minimal hits. We currently have around 30,000 previews registered so we can't sync that to the local Sqlite Db either, it'd be huge.

To be able to access Apples REST API from our service we use John Sheenans excellent RestSharp library: http://github.com/johnsheehan/RestSharp which works great. We had to make a small mod to the default constructor of the RestClient - you can pull my fork from here: http://github.com/wayne-o/RestSharp

Once you have that, connecting to the Apple Search Api and retrieving data is simples. Start by mapping the API to a class which can proxy the Execute method to the RestSharp RestClient:


public class ITunesApi
    {
        const string BaseUrl = "http://ax.itunes.apple.com/WebObjects/MZStoreServices.woa/wa/wsSearch";

        public ITunesApi()
        {

        }

        public T Execute<t>(RestRequest request) where T : new()
        {
            var client = new RestClient();
            client.BaseUrl = BaseUrl;
            request.RequestFormat = DataFormat.Json;
     
            request.AddParameter("country", "gb", ParameterType.UrlSegment); // used on every request
            var response = client.Execute<t>(request);
            return response.Data;
        }

    }

You may have to edit that to suite your needs. Next you need a model to map the response to:


public class Track
    {
        public Int64 ArtistId { get; set; }
        public Int64 CollectionId { get; set; }
        public Int64 TrackId { get; set; }
        public string ArtistName { get; set; }
        public string CollectionName { get; set; }
        public string TrackName { get; set; }
        public string ArtistViewUrl { get; set; }
        public string CollectionViewUrl { get; set; }
        public string TrackViewUrl { get; set; }
        public string PreviewUrl { get; set; }
        public string ArtworkUrl30 { get; set; }
        public string ArtworkUrl60 { get; set; }
        public string ArtworkUrl100 { get; set; }
        public float CollectionPrice { get; set; }
        public float TrackPrice { get; set; }
        public DateTime ReleaseDate { get; set; }
    }


    public class TrackList : List<Track> { }

Here we're specifying a single record (Track) and the collection which RestSharp can map those records to: TrackList. RestSharp takes care of all the mapping from the JSON response to our collection using Newtonsoft.Json.

Next up we need to create a class to actually implement the calls to the REST service. These classes inherit from our base proxy created earlier. We can create a separate inherited class per type of response from the service. In our case we're only interested in collections of tracks. All of these inherited classes can then reflect the API and call into the base to execute. Here is our implementation:

 


public class TrackCollection : ITunesApi
    {
        RestRequest Request;

        public TrackCollection()
        {
            Request = new RestRequest();
        }

        public List<Track> Results { get; set; }

        public int ResultCount { get; set; }

        /// <summary>
        /// maps to the Search APIs search method
        /// An example URL created from this call: ?term=jack+johnson&limit=25&country=gb&media=music
        /// </summary>
        /// <param name="query"></param>
        /// <returns></returns>
        public TrackCollection Search(string query)
        {
            Request.Resource = "?term={term}&limit=25&country={country}&media={media}&limit=200";
            Request.AddParameter("term", query, ParameterType.UrlSegment);
            Request.AddParameter("media", "music", ParameterType.UrlSegment);

            return Execute<TrackCollection>(Request);

        }
    }


And that's it! Now, to execute searches against the Apple Search API, and get a nice strong typed response we just have to do:


var itunes = new GuideStar.Core.ITunes.TrackCollection();
var it = itunes.Search(actualArtist.Name);

Tap me up if you need any pointers here :)

w://