Introduction
Recently, I wrote about Social Media and strategies for integration. I intentionally didn't go into detail as I wanted to take a more philosophical view on our development processes. I made the distinction between frameworks where community driven libraries thrive, and evolving APIs where they often become the kiss of death for projects.
I believe we need to change the way we work with Social Media APIs and stop trying to create SDKs for these APIs in the technology of our choice. The technologies evolve too quickly and instead we need to embrace the core technologies, whilst keeping the integration layers lightweight.
In this article, I want to give an example of one approach by demonstrating some integration with Facebook. The key point here is that rather than using one of the many .NET libraries which wrap Facebook APIs, I'm instead using a generic library that is entirely decoupled from the Facebook APIs themselves.
Hammock - REST, Easy
Hammock is an open source project built in .NET which facilitates the consumption of RESTFul services in a generic way. It offers support for asynchronous operation, query caching, mocking, and rate limiting among other features. There are of course other libraries which could equally be used.
The Code
The following shows an example of retrieving posts from a user's wall in ASP.NET. We could achieve the same functionality through JavaScript alone, but let's assume we want to do something with the data on the server. This requires that the user has granted the read_stream
permission to the Facebook application and assumes the user is authenticated. In the source code provided, I've shown how to achieve both of these tasks using Social Plugins and JavaScript with minimal effort.
The first thing we need to do is create an instance of Hammock's RestClient
class. This contains the base URI of the service EndPoint and can also contain other default properties such as a UserAgent string
.
IRestClient client = new RestClient
{
Authority = "https://graph.facebook.com/",
UserAgent = "MyFacebookApp"
};
Next we create an instance of Hammock's RestRequest
class. This allows us to make RESTFul calls to a particular path relative to the base EndPoint URI defined above. Using Hammock's API it's then simple to add request parameters to the call. In this case, the user's access_token
is appended to the querystring to provide the required authorization.
var request = new RestRequest
{
Path = string.Concat(UserId, "/feed"),
Method = WebMethod.Get
};
request.AddParameter("access_token", AccessToken);
Note the UserId
and AccessToken
values shown in the sample above are obtained from the currently authenticated Facebook user. In the source code provided, I'm passing these values from an Ajax call triggered by a Social Plugin login event.
OK so far it's easy right? Any changes to the Facebook API means we can quickly add or remove parameters that are sent to the API.
The next step is to make the request and parse the response. This is done using the RestClient
we created earlier.
var response = client.Request(request);
if (response.StatusCode != HttpStatusCode.OK)
{
throw new CommunicationException(
string.Format("The EndPoint {0}{1} returned an unexpected StatusCode {2}",
client.Authority, client.Path, response.StatusCode));
}
var content = response.Content;
OK, so now the interesting bit, and this is where I come back to my point about keeping this lightweight and loosely coupled. We could use Hammock's deserializer to type the response directly to our own object, but that's too rigid for my liking. Instead I want to use the dynamic type. This will allow us to access the JSON properties in a loose fashion which can more easily be changed if the API is updated.
Now I couldn't figure out how to get Hammock's out-of-box deserialization to work with dynamic objects. It may be possible, and if anyone knows, please let me know. Instead I created my own JavaScriptConverter
extension so I can use .NETs in-built JavaScriptSerializer
class. You could also register your own custom deserialization classes via Hammock's interfaces but I've kept it simple.
JavaScriptSerializer serializer = new JavaScriptSerializer();
serializer.RegisterConverters(new[] { new JsonConverter() });
dynamic result = serializer.Deserialize<ExpandoObject>(response.Content);
foreach (dynamic obj in result.data)
{
Response.Write(obj.from.name + " wrote " + obj.message);
}
Static vs Dynamic Typing
The nice thing about ExpandoObject
is that not only does it provide dynamic access to the response object to keep it loosely coupled, but it also implements IDictionary<string, object>
. This means it can easily be converted to a typed object using JavaScriptSerializer
. This is useful if we decide to move the code into a service layer and want to provide a strong typed model to our business layer. Only properties that are defined on both source and target will be mapped across in the conversion, other properties are simply ignored.
public class Post
{
public string Id { get; set; }
public string Message { get; set; }
}
foreach (var obj in result.data)
{
var post = serializer.ConvertToType<Post>(obj);
var message = post.Message;
}
Running The Demo
To run the demo code included, you should replace the Facebook AppId
in value FBHelper
class with your own Facebook application key. See Facebook documentation for more details on how to obtain this.
You will notice in the source code provided that I've created a custom expando class called JsonExpandoObject
. This is because ExpandoObject
throws exceptions if you try to access a property that doesn't exist. My version returns null
instead and therefore works much better with JSON.
Summary
So to summarize, generic third party libraries such as Hammock can be used to speed integration with Social Media APIs. This has the advantage over third party Social Media SDKs in that it keeps the codebase more loosely coupled. In doing so, it allows developers to build applications around long established core technologies and produces a codebase more adaptive to change.
By implementing late binding via dynamic types, you can further decouple hard dependencies on APIs. This is particularly useful for lightweight manipulation of content within the data layer. For passing objects to the business layer, I've shown how JavaScriptSerializer
can be used to quickly convert dynamic types into static types as required.
Static types are of course checked at compile time and offer many advantages over dynamic types. The trick here is that we are able to leverage static types in our business layer, but map/convert from objects which are late-bound to API code. This mapping/conversion code becomes the single touch point for maintenance when APIs change.
The example included also shows how we can leverage the emerging Social Plugins and JavaScript APIs which are more resilient to change. These can be used for core functionality and should always be favoured where possible.