Who Is Your ‘Biggest Fan’ on Facebook? Navigating the Facebook Graph API ~ 2016 Tutorial

Before we begin, here’s a working example of this quick Facebook app on my Github 🙂

facebook-api1

There are a few (or a lot, depending on your excitement) cool things you can do with the Facebook Graph API.

First of all, what is the Graph API?

  1. In short, it’s our way of getting Facebook goodies like posts, pictures, status updates, friends list, all that good stuff. We can also post data (AKA update our status) using the Graph API.

For this mini blog tutorial, I’m going to cover the getting part.

In particular, I’ll be demonstrating how to find:

  1. Your most liked posts
  2. The friends who most like your posts (your biggest fans)

I’ll be using JavaScript and Python for this tutorial. No worries if these languages aren’t your go-to; the concepts I cover in this tutorial are constant across all languages.

Let’s roll.

1. Boilerplate (boring stuff) out of the way

First, let’s set up a very simple JavaScript SDK so we can talk to Facebook using JavaScript.

I didn’t want to waste precious code space with boilerplate code, so check it out my Github

2. Basic GET request

Let’s do a basic GET request. Let’s get all my posts, messages, stories along with the likes and comments associated with each post.

function getPosts() {
   FB.api('me/posts/?fields=comments.summary(true),likes.summary(true).fields(name), message,  story',
   function(response) {
       passPosts(JSON.stringify(response))
   });
} 

Ignore the passPosts() function for now

This returns a JSON response as such:

{
 "data": [
     {
      "message": "something about the bao",
      "story": "Nikhil Bhaskar updated his profile picture.",
      "id": "[id of post]",
      "likes": {
        "data": [
          {
            "id": "[id of liker]"
            "name": "[name of liker]"
          },
         ],
       "summary": {
          "total_count": [num of likes],
          "can_like": true,
          "has_liked": false
        }
      },
      ....{}, {}, {}
     ],
    "paging": {
      "previous": "[url]",
      "next": "[url]"
     }
 }

Notice how our result has been paginated. In other words, to actually get all of our posts, we need to run an API call again, on the “paging”:”next”: url.

We should avoid multiple API calls whenever necessary, so let’s slightly modify our basic GET request.

'me/posts/?limit=5000&fields=comments.summary(true),likes.summary(true).fields(name), message,  story'

Notice how now, we include a limit of 5000 posts. It seems to me that this is the max limit we can set (I’m not sure; it was more trial & error here). This way, we get as many posts as we can in one API call. Consequently, we greatly reduce the number of API calls we make.

Learner’s check:

  1. Our ‘response’ object is a JavaScript object. In order for us to easily pass it around we convert it to a string with JSON.stringify()

3. AJAX call to Python

Let’s pass our JSON response to our Python backend so we can further process it.

function passPosts(userPosts){
        $.ajax({
          method: "POST",
          url: "/fb_login/",
          data: { 
            "user_posts": userPosts
            }
        })
        .success(function(data) {
          //handle results
        });
      }

Learner’s check

  1. We call our AJAX function (POST) to the url route ‘fb_login’, with our userPosts

4. Python ~ Get the AJAX POST data

Side note: I am using Django. You can use whatever framework (or no framework) you want

In views.py, let’s get our Facebook API response:

def fb_login(request):
	if request.method == 'POST':

                all_posts_dict = get_all_posts_dict(request.POST['user_posts'])
		
               '''Ignore rest of function for now
		all_posts_dict['data'] = remove_dicts_from_list_based_on_key(all_posts_dict, 'likes')

		my_most_liked_post = sort_posts_dict_by_likes(all_posts_dict)[0]
		print my_most_liked_post
                '''
	return render(request, 'talentur/fb_login.html')

What does ‘get_all_posts_dict(arg)’ do?

def get_all_posts_dict(response):
	return tornado_all_posts_dict(string_to_dict(response))

As you can see, it calls 2 functions. So it does 2 tasks:

  1. Convert our response to a Python dictionary
  2. Call a function on this dictionary to get all of our posts (remember, the JSON response we got was paginated)

Here, we achieve task 1 with our string_to_dict function:

def string_to_dict(json_string):
    return json.loads(json_string)

And here, we call a recursive function tornado_all_posts_dict to achieve task 2:

def tornado_all_posts_dict(response_dict, master_posts = None ):
	master_posts = {'data':[]} if master_posts is None else master_posts
	posts = response_dict['data']
	master_posts['data'] = master_posts['data'] + posts
	if 'paging' in response_dict and 'next' in response_dict['paging']:
		r = requests.get(response_dict['paging']['next']).json()
		tornado_all_posts_dict(r, master_posts)
	return master_posts

5. Find your most liked posts

We gotta do a little clean up, first. As you’ve noticed, the all_posts_dict is a Python dictionary with a “data” property.

“data” is a list of several dictionaries. Each dictionary in “data” is basically a post/message/story, etc. The problem is that some of these dictionaries don’t have a “likes” property.

Example:

{
      "id": "[id]"
}, ...

These are probably just occurrences when you change your cover photo to a photo you’ve already used before, for example. Although there are “likes” associated with your cover photo, there are no “likes” associated with the act of updating your cover photo back to this old picture. Make sense?

So, let’s remove all the dictionaries in “data” that have no “likes” property

def remove_dicts_from_list_based_on_key(response_dict, key):
	the_list = response_dict['data']
	return [dicti for dicti in the_list if key in dicti]

So, in views.py, in def fb_login function, add:

all_posts_dict['data'] = remove_dicts_from_list_based_on_key(all_posts_dict, 'likes')

Now, we can sort our all_posts_dict by “likes”:

def sort_posts_dict_by_likes(response_dict):
	list_of_user_post_objects = response_dict['data']
	list_of_user_post_objects = sorted(list_of_user_post_objects, key=lambda k: -k['likes']['summary']['total_count']) 
	return list_of_user_post_objects

Learner’s check

  1. “likes” has a “summary” property, which in turn has a “total_count property”
  2. “total_count” is the number we care about here
  3. -k because are sorting in descending order

Now, in views.py, the def fb_login function should look like this:

def fb_login(request):
	if request.method == 'POST':

		all_posts_dict = get_all_posts_dict(request.POST['user_posts'])
		all_posts_dict['data'] = remove_dicts_from_list_based_on_key(all_posts_dict, 'likes')

		my_most_liked_post = sort_posts_dict_by_likes(all_posts_dict)[0]
		print my_most_liked_post
		
	return render(request, 'talentur/fb_login.html')

Our response:

{u'message': u'AHAHAHAHHA', u'id': u'1090366184360236_310878925642303', u'comments': {u'data': [], u'summary': {u'total_count': 171, u'can_comment': True, u'order': u'chronological'}}, u'likes': {u'data': [], u'summary': {u'total_count': 1643, u'has_liked': False, u'can_like': True}}}

This was a post I shared a long time ago. Got over a 1000 likes, haha

65793_310878908975638_1907833459_n

Obviously, our actual result is just a Python dictionary. But you can use its id to get everything associated with this post.

Let’s move on..

6. Find your biggest fans

First, let’s put every single friend who liked your posts into a list of tuples. This tuple will contain the id and name of your friend

def liker_ids_tornado(response, like_ids_list = None):
	like_ids_list = [] if like_ids_list is None else like_ids_list
	data_list = response['data']

	for post_message_story in data_list:
		if 'likes' in post_message_story:
			for liker in post_message_story['likes']['data']:
				like_ids_list.append((liker['id'], liker['name']))
	if 'paging' in response and 'next' in response['paging']:
		r = requests.get(response['paging']['next']).json()
		liker_ids_tornado(r, like_ids_list)
	return like_ids_list

Now, let’s use the convenient Counter() function from the ‘collections’ module

def get_most_likers(like_ids_list):
	id_results_dict = Counter(like_ids_list)
	return id_results_dict

Here’s what our def fb_login function looks like now:

def fb_login(request):
	if request.method == 'POST':

		all_posts_dict = get_all_posts_dict(request.POST['user_posts'])
		all_posts_dict['data'] = remove_dicts_from_list_based_on_key(all_posts_dict, 'likes')

		like_ids_list = liker_ids_tornado(all_posts_dict)
		my_biggest_fans = get_most_likers(like_ids_list)
		print my_biggest_fans

	return render(request, 'talentur/fb_login.html')

Our response:

Counter({(u'id', u'Name'): 101, (u'id2', u'Name2'):97...}) 

The result is a Counter, which is a subclass of a Dictionary. So, my ‘biggest fan’ (who I won’t disclose here) has given me a total of 101 likes.

There you have it. A little Facebook insight for ya.

Enjoy 🙂

Once again, here’s a working example of this quick Facebook app on my Github 🙂

Originally Posted at: Who Is Your ‘Biggest Fan’ on Facebook? Navigating the Facebook Graph API ~ 2016 Tutorial

Leave a Reply

Your email address will not be published. Required fields are marked *