Graph API

Alex Koppel edited this page Feb 28, 2017 · 53 revisions

The Graph API is the core of Facebook’s API interface. Let’s play with it.

Graph API in your browser!

Important side note: did you know you can play with the Graph API in your browser? It’s one of my favorite aspects of the API. Facebook has a Graph API Explorer, which lets you get an access token and explore the Graph easily. You can also make requests directly in your browser; for each example coming up, I include a link to the equivalent query. (If you haven’t been to http://graph.facebook.com, you should definitely click through and play with the results.)

Initializing

First, you need to create your API object that you will use to make your calls. Most calls require an access token to access private or restricted data. We’ll go over getting an access token in a moment. For now, head over to the Graph API Explorer and copy one from that tool.

@graph = Koala::Facebook::API.new(access_token)

Getting public data

Let’s get some data from Facebook.  To learn about an object, just use the get_object method.  For instance, you can learn about yourself:

# http://graph.facebook.com/me
@graph.get_object("me")
# => {"name"=>"Alex Koppel", "id"=>"2905623", "last_name"=>"Koppel", "link"=>"http://www.facebook.com/koppel", "first_name"=>"Alex"}

And Pages:

# http://graph.facebook.com/facebook
@graph.get_object("facebook")
# => {"name"=>"Facebook", "id"=>"7204941866", ....}

You can get certain also Page’s feed:

# http://graph.facebook.com/facebook/feed
client = Koala::Facebook::API.new(oauth_token)
client.get_connection('facebook', 'posts', {
  limit: @options[:max_items],
  fields: ['message', 'id', 'from', 'type', 'picture', 'link', 'created_time', 'updated_time']
})

Note: for pictures, you can pass a ‘type’ hash key with a value of ‘small’, ‘normal’, ‘large’, or ‘square’ to obtain different sizes, with the default being ‘square’. Also, you may need the user_photos permission.

As well as details about individual public stories:

# http://graph.facebook.com/7204941866_117111188317384
@graph.get_object("7204941866_117111188317384")
# => {"name"=>"Bare Escentuals Cosmetics",
#     "message"=>"We've just launched the Bare Escentuals "Mom & Me" application!",
#     "likes"=>3,
#     ....
#    }

If you want to retrieve several objects without having to make a bunch of facebook calls, just call the get_objects method.

# https://graph.facebook.com/?ids=109856845694262,103914006312563
@graph.get_objects([109856845694262,103914006312563])
# => {"109856845694262" => {"id"=>"109856845694262", "name"=>"Cupe Coy, Netherlands Antilles", . . .       },
#     "103914006312563" => {"id"=>"103914006312563", "name"=>"Perrine, Florida", . . . }}

Some Facebook calls take three parts — for instance, let’s say you want to get a user’s mutual friends. Easy:

# https://graph.facebook.com/me/mutualfriends/FRIEND_ID
@graph.get_connections("me", "mutualfriends/#{friend_id}")
# => [{"name"=>"Alex Koppel", ....}, ....]

You can also search for users/pages/events/groups for the keyword of your choice:

# http://graph.facebook.com/search?q=koala&type=place
@graph.search('koala', type: :place)
# => [{"category"=>"Attractions/things to do", ...
#     "name"=>"Maru Koala & Animal Park"}]}

To request user’s birthday (and other special fields) you need to send your FB application for special review with indication of reason why you need this information. Once this step is done you can get access to birthday by follow code:

@graph.get_object("me?fields=birthday")

Writing to the Graph

Reading’s all well and good, but no discussion of the graph would be complete without some writing. In order to write to the social graph, you’ll need to prompt your user for the appropriate extended permissions (see the OAuth section).

For the sake of simplicity, let’s assume the token we got above has the right permissions; otherwise, you’ll get an error. (Since writing to the graph involves sending POST requests, the browser follow-along unfortunately has to end.)

Let’s start by posting to our own walls using the put_wall_post method.

@graph.put_wall_post("hey, i'm learning koala")
# => {"id"=>"2905623_123183957698327"}

Oops — we misspelled Koala! How embarrassing.

@graph.delete_object("2905623_123183957698327")
# => true

Let’s never speak of that again, okay?

Speaking of family, Mother’s Day was coming up when I wrote this. Let’s go back to that earlier post about that Mother’s Day app, and like it.

@graph.put_like("7204941866_117111188317384")
# => true

Now it has 4 likes:

@graph.get_object("7204941866_117111188317384")
# => {"message"=>"We've just launched the Bare Escentuals "Mom & Me" application", "likes"=>4...}

Actually, changed my mind. I’m not a huge cosmetics fan.

@graph.delete_like("7204941866_117111188317384")
# => true

Personal confession: I still haven’t picked out a gift for my mom. What’s Facebook for, if not to talk about things like that?

@graph.put_comment("7204941866_117111188317384", "Can't believe Mother's Day's just a week away!  I'd better get on that gift.")
# => {"id"=>"7204941866_117111188317384_448625"} # ID of the comment

Turned out to be quite the adventure, so I’ll post a note about it:

@graph.put_connections("me", "notes", :subject => "Finding my mom a gift: An Epic Odyssey", :message=> all_the_details)
# this works for other connections too -- links, events, etc.
# def put_connections(id, connection_name, args = {}, options = {})

That’s more or less it for the Graph API. All the calls you just saw wrap a few generic methods (get_object, get_connections, put_connections, delete_object, etc.), which allow you access to the entire Graph API. Facebook has done a great job of designing the API and keeping interface stable and consistent; these basic accessors should function for all the methods out there and (so far so good) anything new they release in the future.

Retrieving Pages of Results

Thanks to jagthedrummer for this contribution!

When fetching data from Facebook that returns a list of results (i.e. using API#get_connections or API#search) Facebook returns a limited number of results per request. To help make paging through these results easier, Koala returns a GraphCollection object, a subclass of Array, that includes a few methods to ease getting the next and previous pages of results.

@result = @graph.get_connections('me', 'feed')
@result.class
# => Koala::Facebook::GraphCollection

# You can use a GraphCollection just like a normal Array or results
@result.first
# => {"actions" => [], "message" => "This my feed message.", ...}

To get the next (or previous) page of results, use the next_page (or previous_page) method on a GraphCollection.

@next_page = @result.next_page
# => [{"actions" => [], "message" => "This my feed message.", ...}, ...]

@next_page.class
# => Koala::Facebook::GraphCollection

GraphCollections also provide data about the response headers, useful for checking etags or rate limits:

@result.headers
# => {"some" => "headers"}

Paging Across Multiple (User) Requests

While paging through results is fun, most of the time you’ll want to fetch the next page of results only when requested by the user. The next_page_params and previous_page_params methods in conjunction with API#get_page method makes this a snap.

API#next_page_params returns an array with two entries describing the API URL to fetch the next page of results: the path and a hash of parameters.

@results.next_page_params
# => ['"me/feed", {"limit => "25", "access_token" => "...", ...}]

Using the result of next_page_params as the single argument to API#get_page you can retrieve the next page of your results.

Here’s an example using Rails (see below for other frameworks):

# /app/controllers/foo_controller.rb
def index
  # get the first page, or a next/previous page if appropriate params are sent
  @results = params[:page] ? @graph.get_page(params[:page]) : @graph.get_connections("me", "feed")
end
# /app/views/foo/index.html.erb
<% @results.each do |result| %>
  <!-- Display each result -->
<% end %>

<%= link_to 'Previous', url_for(:page => @results.previous_page_params) %>
<%= link_to 'Next', url_for(:page => @results.next_page_params) %>

Notice that API#get_connections only needs to be called once, when you fetch the first page of results. By using next_page_params to populate the “page” URL parameter, you can use params[:page] as a single parameter to API#get_page to get the next set of results (as above).

This example takes advantage of how Rails serializes an array as URL parameters (and how Rails interprets URL parameters when handling requests.) Even without this functionality, however, creating appropriate parameters to use from next_page_params should be fairly straight forward — if you’re using Sinatra or another framework, check out this comment for an example of how to traverse pages without using the Rails helpers.

Special Topics

A few Graph API odds and ends that have come up over the years.

Posting unencoded text

In rare cases it can be useful to post unencoded parameters directly to Facebook — for instance, at one point posting certain strings (like <center></center> or %0D%0A) would add a line break to a wall post. All Koala form parameters are URL encoded, but it’s easy to post unencoded strings by constructing parameters yourself:

# this is posted without encoding and (at one time) would show up on two lines
@graph.put_connections("me", "feed?message=foo%0D%0Abar")

Nested fields

Imagine you also need the picture of an post author and you don’t want to make a separate graph call for every post to retrieve it. You can use a nested field for it:

posts = @graph.get_connection(<page_id>, 'posts', fields: ['from{id, name, picture}', 'message', 'created_time', 'name', 'full_picture', 'source'])

If the Graph API returns false

In some cases — for instance, if the user has opted out of the Facebook Platform entirely — your Graph API calls may return false instead of the expected object. It’s rare, but it does happen — something to keep in mind as you develop. See http://forum.developers.facebook.net/viewtopic.php?id=61050.