This is a repost from an earlier post. My earlier blog exploded messily so I am reposting some of my technical posts from the past
Facebook has opened up access to most of their data through their
Graph API. I bitch elsewhere about their decision to implement
OAuth 2.0, but that should not detract from the fact that this new REST based interface is simple, straightforward, and a breeze to use. The number of requests to parse a user’s feed is not insignificant compared to what is possible with
FQL.
For our
Kynetx Code Run, we have already done some pretty exciting things with the FB API.
Previously, Kynetx has treated data sources as read-only operations. With this release, we have introduced writes as a user action. The format is similar to the usual get syntax, but it is an action so it needs to be called from the Action part of your rule (use it like you would
notify or other actions like:
after,
before,
float…)
Facebook calls their data the Social Graph. I may use that term interchangeably with Facebook or the Graph API.
Skip to the examples
Create a Facebook application
The easy way that I did it was to just go to the
Facebook Developer page. You will need to accept the FB terms and conditions and name your app. It doesn’t matter what you name your app, but the name will be used by Facebook during the authorization process and for any content that you create through the API.
For our purposes, we are only interested in a couple bits of information; however, this does create a real app so you should spend some time filling in profiles, adding logos and generally tarting-up your app.
If you are familiar with OAuth, you know that you need an id and secret for the authorization process. Conveniently for us, Facebook takes us straight to the required information
The Graph API uses the
Application ID and
Secret as the
consumer_key and consumer_secret respectively.
It is
important that you do the next step correctly! Set your Facebook application’s
Connect URL to
http://cs.kobj.net:80/ruleset/fb_callback/ Facebook uses the Connect URL as an additional security measure to make sure developers are not up to something naughty. As part of the OAuth process, KRL tells FB to send a token to a URL on our server (That’s how your user can log in and authorize through Facebook and never give out their username and password). If your Connect URL and the URL that Kynetx provides don’t match, the authorization process will
FAIL.
FACebook’s social graph
The Graph API exposes several objects from the social graph. From what I have read on the forums, there are a few objects that were available in the old API or FQL that are not available from the Graph API. I would recommend that you become familiar with what information is available and where to find it. From the Facebook documentation, these are the objects that are available
Create your Kynetx Application
For KRL, the process of integrating Facebook into your application is the same as the process we use for
Twitter and
Google. The Twitter documentation is fairly extensive, so I will just hit the highlights.
Set up your facebook application information in the META section
key facebook {
"consumer_key" : "892934849920029",
"consumer_secret" : "1a3836d9d025f9e2738bb50976"
}
Create first rule to AUTHORIZE your user with Facebook
rule auth_app is active {
select using ".*" setting ()
if (not facebook:authorized())
then
facebook:authorize(["publish_stream","email","user_photos","read_stream",
"user_notes","offline_access","user_about_me","user_notes",
"user_photos","user_likes","user_online_presence"
])
with opacity = 1 and
sticky = true;
fired {
last;
}
}
Before any FB request, KRL checks to see if the application has been authorized to access the current user’s information. The auth_app rule explicitly runs that check for you. If the user does not have a valid OAuth token, the OAuth authorization process is started.
Let’s examine the authorize command in more detail:
facebook:authorize(["publish_stream","email","user_photos",
"read_stream","user_notes","offline_access","user_about_me",
"user_notes","user_photos","user_likes","user_online_presence"
])
authorize takes as an argument an array of
extended permissions. They are separated into two major categories: Publishing and Data. Data is further divided into User and Friends permissions.
Permissions
Table 1 Facebook's extended permissions
Publishing |
Data |
User |
Friend |
publish_stream |
email |
|
create_event |
read_insights |
|
rsvp_event |
read_stream |
|
offline_access |
user_about_me |
friends_about_me |
|
user_activities |
friends_activities |
|
user_birthday |
friends_birthday |
|
user_education_history |
friends_education_history |
|
user_events |
friends_events |
|
user_groups |
friends_groups |
|
user_hometown |
friends_hometown |
|
user_interests |
friends_interests |
|
user_likes |
friends_likes |
|
user_location |
friends_location |
|
user_notes |
friends_notes |
|
user_online_presence |
friends_online_presence |
|
user_photo_video_tags |
friends_photo_video_tags |
|
user_photos |
friends_photos |
|
user_relationships |
friends_relationships |
|
user_religion_politics |
friends_religion_politics |
|
user_status |
friends_status |
|
user_videos |
friends_videos |
|
user_website |
friends_website |
|
user_work_history |
friends_work_history |
|
read_friendlists |
|
|
read_requests |
|
The full breakdown on permissions is found on
Facebook. Two permissions which are particularly relevant to KRL are
publish_stream and
offline_access. Without publish_stream permission, you won’t be able to post to your user or their friends accounts. Without offline_access, users would have to be logged into facebook for your queries to work. Here are the allowed values—any other values will just be ignored.
I suspect that some might be tempted to pile all the permissions into an authorize request. Aside from missing the point of writing context sensitive rules to fulfill specific needs, there is an Internet Explorer limitation which restricts the size of an HTTP query. Just to keep you from piling on permissions, I’m not going to tell you what that limit is.
Despite the permissions the user has authorized, there is often public data which is available regardless of authorization. Do not be misled by a user’s public information into thinking that your app is authorized to request the information; ie: to allow other people to find you in a friend search, your first and last name has public permissions. So anyone who types the URL:
https://graph.facebook.com/100001078761602/ will see the information that Kay Netticks has made public.
Connections
Connections are the way that facebook links objects together. Most every object has connections to other objects. This allows a group to have members, photos and a news feed. A status message only has comments. The user object has many, many connections—basically all the various stuff that you can see on your FB home page.
Not specifying a connection will return the profile information for the current object.
For convenience, there is a special function
facebook:connections() which will tell you what are valid connections for a particular object.
IDs
Almost every object in the Social Graph has an id. Getting information for a particular object is as easy as providing the correct id. If you don’t specify an id, the currently authorized user is used as the default object. Facebook has a special alias for the currently authorized user “me”. KRL doesn’t require you to specify an id, but you may see request urls in your debug statements that use “me” so you should be aware of the meaning.
Paging
Several of the Social Graph queries can return multiple items. Facebook provides some paging functions so you have some control over which and how many results are returned.
limit and offset both require integers for their values. With limit, you can specify how many items you want to receive for one request. Offset allows you to skip any number of elements before you start returning results.
Since and until operate like a min and max date respectively. They take a date as an argument, but that date can be formatted according to what the PHP
strtotime function allows. That means that ‘2010-04-01’ and ‘yesterday’ are both valid values. The
online PHP manual gives these as valid examples:
Valid formats for FBs since and until query parameters
"now”
"10 September 2000"
"+1 day”
"+1 week”
"+1 week 2 days 4 hours 2 seconds"
"next Thursday"
"last Monday”
fields
If you are only interested in select fields of a Social Graph object, you may use the fields argument to limit the response to only your desired fields. The argument takes the form:
- fields : <string> | <CSV string> | [<string1>,…,<stringN>]
A field name string, comma separated list of field names, or an array of field names are all valid values for fields. For convenience, there is a special function facebook:fields() which will tell you what are valid fields for a particular object.
Queries
Query syntax should be familiar to KRL users. There are 5 basic facebook queries which are available in KRL. Each can accept a hash as an argument, though facebook:search is the only function that requires an argument. Not specifying an id, will perform the query in the context of the currently authorized user.
facebook:metadata()
I debated whether I should provide access to the metadata query. The metadata is designed to allow for introspection. That’s kind of like telling you what know about what you know about an object. It returns profile information, but it also returns preformatted url references to all of the connections that are valid for your object. It’s a good idea, but when you have a token with your metadata request and are defaulting to the currently authorized user (“me”), the urls come pre-configured with the access token attached. That may not make much difference for people who are writing pure javascript implementations of the Social Graph, but KRL is a MUCH more secure environment and I don’t like the idea of leaving that token lying around.
facebook:picture()
- optional
- id :<string>
- type : square | small | large
Most all objects have a picture or an icon associated with them. When you make a request for the picture, Facebook returns a redirect to the actual URL. I follow that re-direct and return the actual URL for the picture. This makes a picture call a little bit more complicated so bear that in mind if you are going to do large amounts of picture requests. If it would be more useful, I could include something like a ‘nofollow’ tag so that I just return the location of the redirect, but that is currently not provided
facebook:search()
- required
- type : post | user | page | event | group | home
- q : <string>
- optional
- id :<string>
I haven’t found FB’s search functionality to be terribly robust. As I say to my kids, “You get what you get and you don’t throw a fuss”. If you find that you aren’t getting the results that you think you should, grab the url from the debug and enter it with your browser to see if it’s just bad indexing on FB’s part.
home is a special case where the search will be performed only on the currently authorized users news feed or whomever is specified by the optional id parameter
facebook:get()
- optional
- id :<string>
- connection: <string>
- type : <facebook object>
If you would like to follow a connection; ie: get all the comments associated with a post, just provide a “connection” : <value>. If you would like KRL to do some sanity checking, you can use the optional “type” : <object> syntax in conjunction with connection. KRL will check to see if your connection is valid for that type of object. If not, a warning will be printed to your console.
facebook:ids()
- required
- ids :<string> | <CSV string> | [<string1..stringN>] | url
This method allows you to get profile information for multiple ids. <string> can be a username or the numeric id (it is not guaranteed that the user will have a username defined).
An optional usage is to provide a URL instead of an id. You can use this to look up or check to see if there is an object already associated to a URL in Social Graph
POSTS
Table 2 Posting to Facebook
Connection |
Requires* |
Arguments |
feed (wall) |
<profile id> |
- message
- picture
- link
- name
- caption
- description
|
comments |
<post id> |
|
likes |
<post id> |
|
notes |
<profile id> |
|
links |
<profile id> |
|
events |
<profile id> |
|
attending (events) |
<event id> |
|
maybe (events) |
<event id> |
|
declined (events) |
<event id> |
|
albums |
<profile id> |
|
photos |
<album id> |
|
Facebook allows you to create new instances of a few of their Social Graph objects; ie: write a message on someone’s wall. This requires the
publish_stream permission from the user. What information you supply is determined by the type of object that you are trying to create.
Here are the objects that you can publish via the Graph API:
Syntax for publishing is very simple, but remember that publishing is an
action. In this case, the action is not producing JavaScript, but posting data to the Graph API.
facebook:post()
- required
- connection : <string>
- id: <string>
- optional
- <arg> : <string>
See
table 2 for a list of what arguments are available for each connection.
*id is optional when the connection requires a profile id. As in previous cases, if the id is not supplied, it will default to the id of the currently authorized user. The following connections require a profile id: feed, notes, links, events, albums. I would suggest always supplying the id for consistency.
The post method cross checks the connection type with the permitted arguments. If an argument is not associated with the connection, it will just be ignored.
For convenience, there is a special function
facebook:writes() which will tell you what are valid argument keywords for a particular connection.
Examples
Request for metadata by id
facebook:metadata({“id” : “100001078761602”});
returns: JSON
Request for metadata for currently authorized user
facebook:metadata();
returns: JSON
Writable fields/allowed parameters for a Facebook object
facebook:writes(“feed”);
returns: Array
Post a message to a user’s feed
facebook:post({"id" : "100001078761602",
"connection" : "feed",
"message" : "Contactless not, swipe again",
"picture" : "https://kynetx-images.s3.amazonaws.com/KynetxLogo273.png",
"link" : "http://www.kynetx.com",
"name" : "Things I like",
"description" : "I am integrated into Facebook!" });
“like” a post
facebook:post({"id" : "641349049_124260134272950",
"connection" : "likes"});
Search for these ids and return their profile data
facebook:ids(“ids” : [“100001078761602”,”116360591732083”]);
returns: JSON
Search the Facebook Social Graph to see if a URL has an ID
facebook:ids(“ids” : “http://www.kynetx.com”);
returns: JSON
Request specific user’s feed
facebook:get({“id” : “100001078761602”, ”connection” : “feed”});
returns: JSON
Request default user’s albums
facebook:get({”connection” : “albums”});
returns: JSON
Request default user’s home with optional “type” syntax
facebook:get({”connection” : “home”, ”type” : “user”});
returns: JSON
Request an object by id
facebook:get({”id” : “511048495_446064733495”});
returns: JSON
Request all the messages posted to a specific object (link)
facebook:get({“id” : “511048495_446064733495”, ”connection” : “comments”});
returns: JSON
Search the Social Graph for a page
facebook:search({”type” : “page”, ”q” : “Lehi, Utah”});
returns: JSON
Search the Social Graph for a user
facebook:search({”type” : “user”, ”q” : “Steve Fulling”});
returns: JSON
Get the large picture associated with the currently authorized user
facebook:picture({“type” : “large”});
returns: url (string)
Get the picture for an object
facebook:picture({“id” : “116360591732083”});
returns: url (string)
Request for object picture by id and type
facebook:picture({“id” : “100001078761602”, ”type” : “small”});
returns: url (string)
Allowed connections for a Facebook object
facebook:connections(“page”);
returns: Array
facebook:fields()
Allowed fields for a Facebook object
facebook:fields(“user”);
returns: Array
Authorization Action with desired Facebook permissions
facebook:authorize(["publish_stream","email","user_photos","read_stream"]);
Authorization predicate
facebook:authorized();
returns: true or false
limit
Search the Social Graph for a group and limit results to 3
facebook:search({"type" : "post",
"q" : "bacon",
"limit" : 3});
returns: JSON
Search the Social Graph for a user and start with the 20th object
facebook:search({"type" : "user",
"q" : "John Smith",
"offset" : 20});
returns: JSON
until
Search the Social Graph for users named who signed up before 2010-05-18
facebook:search({"connection" : "feed",
"q" : "John Smith",
"until" : "2010-05-08"});
returns: JSON
since
Search default user’s news for posts made within last day
facebook:get({"connection" : "feed",
"since" : "yesterday”});
returns: JSON
Get specific fields for the default user
facebook:get({“fields” : [“last_name”,”email”]});
returns: JSON