share_counts Ruby gem: The easiest way to check how many times a URL has been shared on social networks!

share-counts-gem-social-networks

I was looking for a way to quickly check at once how many times a URL has been shared on the most popular social networks and aggregators, but I couldn’t find any. So I wrote some code to query these social networks’ APIs and I thought it may be useful to others, so why not gem it up? In fact, I already got the confirmation that may be useful to others since I just published the gem hours ago and despite I am talking about it only now, I saw that almost 20 people had already downloaded the gem!At the moment, the gem – named share_counts – supports the following social networks and aggregators:

I may add support for other networks if needed, and I will more likely extend the gem with other methods to leverage more of what the APIs offer, so stay tuned.

Using the gem

Github repo: https://github.com/vitobotta/share_counts.

On RubyGems: https://rubygems.org/gems/share_counts/stats.

Once you have installed the gem with the usual gem install share_counts, it’s very easy to use. For example, if you want to check the Reddit score for a story, you can call the method reddit with the URL as argument:

It works the same way with the other networks supported. Only for Facebook there are two methods available rather than one, since Facebook has both “shares” and “likes”:

You can also get both shares and likes together:

Also you can get the share counts for all the supported services in one call or otherwise specify which ones you are interested in:

In these cases you’ll get back a hash instead.

At this point, you may have noticed the message “Redis caching is disabled” being printed with each call. That was because I had the caching disabled. Since I’ve noticed that a) some of these social networks’ APIs aren’t available/working 100% of the time, and b) some of them may do rate limiting if you are making too many requests in a short period of time, the gem also supports caching with Redis.

By default caching is disabled since you may not be running Redis or you may want to use some other caching in your application, or you may not want to use caching at all. So the first step if you do want to use the caching, is to enable it. By default, share_counts assumes that Redis is listening on 127.0.0.1:6379, but you can override this by either setting in advance the global variable $share_counts_cache if you already have a reference to a connection with Redis (and you’re using the same redis gem used by share_counts), or by passing that reference as argument. You can alternatively specify host and port when you enable the caching:

Cached share counts expire by default in 2 minutes, but you can again override this by setting the global variable $share_counts_cache_expire to a value in seconds.

So, let’s compare now using the gem with and without caching:

You can see which URLs have been cached and with which available share counts, with the cached method:

Also, if you need you can clear the cached values:

Notes:

  • If a request fails for one network, its share count won’t be cached and will remain set to nil. This way you can easily know whether a service’s API failed by just checking whether its share count for the given URL is nil or not.
  • Since you may be already using Redis in your app for something else, the gem namespaces the keys so that if you clear the cache, only its keys will be deleted.

A look at the code

The code is on Github if you want to have a look. Here I’ll highlight a few things.

All the methods to retrieve share counts for each supported service are wrapped in the module ShareCounts, as you may already have guessed:

In particular, the try method will try to fetch the requested share count(s) by either making an HTTP request (or multiple requests depending on which share counts are being requested) or, if caching is enabled, from the cache.

Since most of these APIs follow a common pattern, HTTP requests are made with the assumption that APIs will return a JSON response with or without a callback method; if a callback method is provided, then the response is first manipulate to just extract the JSON data we need. The make_request method will attempt a request to a network’s API for a maximum of three times, with a maximum timeout of 2 seconds for each attempt. There’s a reason for this: while I was testing these APIs, I noticed that in most cases if a request didn’t return within a couple seconds, it then either timed out after a long time or returned with a 503 Service Unavailable status code. From this point of view, I must say I was surprised to see that Digg‘s API was likely the least reliable of the bunch, returning a 503 code too often, although I wasn’t making too many requests in a short period of time, so I doubt this was because of rate limiting. Anyway, the combination of a 2 seconds timeout and the three attempts, means we expect a response from each service within a few seconds and that’s a good compromise if you use caching. To make requests, I am using one of my favourite gems, rest-client (from the Github user archiloque‘s fork since it seems to be more up to date than the original one by Heroku‘s Adam Wiggins):

As for the extraction of the actual share counts from each API’s response, I was pleased to see a common pattern in the usage of JSON, so it was as easy as writing a simple method that “queries” the JSON data in a way that somehow recalls XPATH for XML. Arguments are the JSON data and a :selector => “where/the/share/count/is”, single key hash:

The stuff needed for the caching with Redis is in a separate mix-in. If you haven’t used Redis yet, you can see its most basic usage from looking at this code.

To initialise a connection and optionally specify host and port:

To read from and write to Redis:

Then we have methods to return all the cached values used by the gem, and to clear those cached values:

As you can see keys are sort of “namespaced” and I am using inject to build a hash with the cached URLs and share counts.

APIs: a few exceptions to the “rule”

As said, most of the APIs for supported social networks follow a common pattern in their usage of JSON data. However there were two exceptions; a small one with Google Buzz‘s, in that it returns a JavaScript object -instead of an array- having as unique property the URL specified as argument; the value of that property then is the actual share count on Google Buzz. So in this case rather than using the extract_count method as for the other JSON-based APIs, all I had to do is getting the value of that property once parsed the JSON response:

The second exception, instead, is StumbleUpon. I was so surprised and disappointed to see that they don’t have an API yet! (unless I missed it). It looks like StumbleUpon is a little behind the competition on this front. Luckily, despite the lack of an API, it wasn’t much more difficult to fetch share counts for SU too; in this case, once identified the HTML returned when their button is displayed, I could use Nokogiri to extract the share count, using XPATH:

So this was a quick look at the code as it is now, but I expect to add more methods to fetch more information from the APIs, so keep an eye on the Github repo if you plan on using this gem.

Also, if you have any suggestions on what to add or how to improve it, please let me know in the comments.




Have your say!

Please see my comment policy if this is your first time here or if you have any questions regarding comments.