torsdag den 22. marts 2012

Working with Facebook Graph API

Facebook is fast becomming the most updated source of information on a lot of companies, especially in the entertainment industry. This post will help you get event data from Facebook onto your own site.

First thing you need to do is get familiar with Graph API Explorer: https://developers.facebook.com/tools/explorer

It's a wonderful tool that will help you construct your API calls. For this tutorial we will only work with events. Events are however one of the most "fragmented" types of data Facebook offers. To get a full list of events, including all data, for a given page we need to make quite a few requests.

Next thing to do is to setup access to an accesstoken. Facebook requires this token for all API calls outside of Graph Explorer. Basicly what we need is ClientSecret and ClientID. Both of those can be obtained from your Facebook App. If you dont have a Facebook App you should read this article: https://developers.facebook.com/docs/authentication/server-side/

Now we have all our basics in place. I will be using a nightclub called Fabric London for this tutorial.

We will be making a lot of call to Facebook, so the first thing we need to create is a method that can call a URL and return the JSON string.

/// 
        /// Gets stream of data from a given website URL
        /// 
        /// URL of the website        /// String
        public static String GetWebStream(String url)
        {
                // used to build entire input
                var sb = new StringBuilder();

                // used on each read operation
                byte[] buf = new byte[8192];

                // prepare the web page we will be asking for
                var request = (HttpWebRequest)
                    WebRequest.Create(url);

                HttpWebResponse response = null;
                try
                {
                // execute the request
                response = (HttpWebResponse)
                    request.GetResponse();
                }
                catch (Exception e)
                {
                    //Handle error
                }

                // we will read data via the response stream
                var resStream = response.GetResponseStream();

                string tempString = null;
                var count = 0;

                do
                {
                    // fill the buffer with data
                    count = resStream.Read(buf, 0, buf.Length);

                    // make sure we read some data
                    if (count != 0)
                    {
                        // translate from bytes to ASCII text
                        tempString = Encoding.ASCII.GetString(buf, 0, count);

                        // continue building the string
                        sb.Append(tempString);
                    }
                }
                while (count > 0); // any more data to read?

                return sb.ToString();
        }

from here on we can obtain our access token using GetWebStream method
//Get a new and valid authtoken
                var AuthToken =
                    WebStream.GetWebStream("https://graph.facebook.com/oauth/access_token?grant_type=client_credentials&client_id=" +
                                 AppID + "&client_secret=" + AppSecret);

With a valid access token we can now get the first part of our event stream. I have added a few extra parameters to limit it to current events (from today and 1 month forward). We also only want the next 10.

var stream = WebStream.GetWebStream("https://graph.facebook.com/FabricLondon/events?since=today&until=1 month&limit=10&" + AuthToken);

You should now have your stream variable containing a lightweight list of Events held at FabricLondon. But these events are missing certain parameters such as the image, description and how many have signed up already. To dig further into the events we will need to serialize the JSON stream into C# objects. Since MVC3 doesn't ship with a JSON serializer for this sort of task you will need to find one. I personally am very fond of JSON.NET (http://json.codeplex.com/) which makes it very easy to serialize and deserialize between C# objects and JSON.

To serialize we will need to recreate the JSON in C# Classes. You can use the following for events:
private class AttendingCollection
        {
            public List<attending> data { get; set; }
        }

        private class Attending
        {
            public String name { get; set; }
            public String id { get; set; }
            public String attending { get; set; }
        }

        private class LightEventCollection
        {
            public List<lightevent> data { get; set; }
        }

        private class LightEvent
        {
            public String name { get; set; }
            public String start_time { get; set; }
            public String end_time { get; set; }
            public String location { get; set; }
            public String id { get; set; }
        }

        private class Event
        {
            public String id { get; set; }
            public String name { get; set; }
            public String description { get; set; }
            public String start_time { get; set; }
            public String end_time { get; set; }
            public String location { get; set; }
            public String ImageURL { get; set; }

            public Venue venue { get; set; }
            public int Attendees { get; set; }
        }

        private class Venue
        {
            public String latitude { get; set; }
            public String longitude { get; set; }
            public String id { get; set; }
        }

        private class EventViewModel
        {
            public String ID { get; set; }
            public String Description { get; set; }
            public String StartTime { get; set; }
            public String EndTime { get; set; }
            public String ImageURL { get; set; }
            public String Name { get; set; }
            public Venue Venue { get; set; }
            public int Attendees { get; set; }
        }

        private class EventViewModelCollection
        {
            public List<eventviewmodel> events { get; set; }
        }
The ViewModels are our custom made Events that hold all the event info we gather from Facebook.


The stream we got from facebook only contains lightweight events, and we will need to serialize those and get the full events for each of the lightweights:
var lightWeightEvents = JsonConvert.DeserializeObject<lighteventcollection>(stream);
var events = GetEventsGraph(lightWeightEvents.data.ToList(), authToken);

private static IEnumerable<event> GetEventsGraph(IEnumerable<lightevent> lightEvents, String authToken)
        {
            var events = new List<event>();
            foreach (var lightEvent in lightEvents)
            {
                var stream = WebStream.GetWebStream("https://graph.facebook.com/" + lightEvent.id + "&" + authToken); 
                var detailedEvent = JsonConvert.DeserializeObject<event>(stream);

                //Get the amount of people signed up for the event
                var attendee = WebStream.GetWebStream("https://graph.facebook.com/" + lightEvent.id + "/attending?limit=999999&" + authToken);
                var attendees = JsonConvert.DeserializeObject<attendingcollection>(attendee);
                detailedEvent.Attendees = attendees.data.Select(m => m.attending == "attending").Count();
                
                events.Add(detailedEvent);
            }
            return events;
        }
What this method does is iterate across all our lightweights, calling facebook for the full details aswell as getting the list of attendees. Once it's un we can return our full list of events and start creating our custom class.

Here we have our full method:

public static String GetEventViewModels(String stream, String authToken)
        {
            var lightWeightEvents = JsonConvert.DeserializeObject<lighteventcollection>(stream);
            var events = GetEventsGraph(lightWeightEvents.data.ToList(), authToken);
            var viewModels = events.Select(item => new EventViewModel()
                                                       {
                                                           ID = item.id, 
                                                           Description = item.description, 
                                                           StartTime = item.start_time, 
                                                           EndTime = item.end_time, 
                                                           Name = item.name, 
                                                           ImageURL = item.ImageURL, 
                                                           Venue = item.venue,
                                                           Attendees = item.Attendees
                                                       }).ToList();
             viewModels.Sort((x, y) => DateTime.Parse(x.StartTime).CompareTo(DateTime.Parse(y.StartTime)));
            var col = new EventViewModelCollection()
                       {
                           events = viewModels
                       };

            return JsonConvert.SerializeObject(col);
        }
We end it up by serializing the data back into JSON, ready to send to your view or client.

For the full FacebookEvent class see this pastebin: http://pastebin.com/jXheywqi

Ingen kommentarer:

Send en kommentar