Documentation

Welcome to the restfb documentation.

Here you find basic information how the restfb library is used. All the different topics are handled here, but we only give a overview over the usage of the library. If you need a more in depth view and more information have a look at the cookbook. There you’ll find a lot of receipes that cover the advanced usage of restfb.

Fetching

The simplest way to fetch an object from Facebook is the fetchObject method. To use this method you need at least the endpoint you want to access and the result type.

The endpoint can be found in the Facebook Graph API Reference. There you can find the correct syntax for the endpoint and how the response json is defined by Facebook. The type you have to provide is a concrete mapping between the json and a java object.

// For all API calls, you need to tell RestFB how to turn the JSON
// returned by Facebook into Java objects.  In this case, the data
// we get back should be mapped to the User and Page types, respectively.
// You can write your own types too!

User user = facebookClient.fetchObject("me", User.class);
Page page = facebookClient.fetchObject("cocacola", Page.class, 
                 Parameter.with("fields", "fan_count"));

out.println("User name: " + user.getName());
out.println("Page likes: " + page.getFanCount());

See Graph API documentation

If you want to fetch several objects at once and these objects are very similar, you can use the “multiple ids” request. A simple way to fetch two user objects is a call like:

JsonObject fetchObjectsResults =
  facebookClient.fetchObjects(Arrays.asList("me", "123456789"), 
           JsonObject.class, Parameter.with("fields","name,id"));

As you can see, you use the fetchObjects method and supply a list of ids as first parameter. You get a JsonObject as a response with the previously provided ids as names in this JsonObject.

{
  "me": {
    "name": "My User",
    "id": "98765432"
  },
  "123456789": {
    "name": "Example User",
    "id": "123456789"
  }
}

If you prefer to work with a strongly-typed object instead of a basic JsonObject, you can define your own. For example, we fetch the user me and the page cocacola. You may even mix different ids. But please pay attention to the fields you request: you may only request intersecting fields, otherwise you will receive an error response.

FetchObjectsResults fetchObjectsResults =
  facebookClient.fetchObjects(Arrays.asList("me", "cocacola"), 
         FetchObjectsResults.class);

out.println("User name: " + fetchObjectsResults.me.getName());
out.println("Page likes: " + fetchObjectsResults.page.getLikes());

...

// Holds results from a "fetchObjects" call.
// You need to write this class yourself!

public class FetchObjectsResults {
  @Facebook
  User me;

  // If the Facebook property name doesn't match
  // the Java field name, specify the Facebook 
  // field name in the annotation.

  @Facebook("cocacola")
  Page page;
}

Additionally, you may work with edges. If all ids have the requested edge you’ll get the requested data. If one id is missing this edge, you’ll get an error instead.

GET graph.facebook.com
  /photos?ids={user-id-a},{user-id-b}

The request is equivalent to these requests:

GET graph.facebook.com
  /{user-id-a}/photos
  
GET graph.facebook.com
  /{user-id-b}/photos

Summary of multiple ids misusage

  1. ids with non intersecting fields requested: Only intersecting fields are allowed.
  2. Edges are requested that are not part of all ids.
  3. More than 50 ids requested: Only 50 ids are allowed in one request.

Multiple ids and the request limit

Although you make only one request, Facebook counts every id. If you provide e.g. 10 ids, the single request is counted as 10.

You should check your implementation: If you have many ids of the same type, a "multiple ids" request can be the better solution. On the other hand, it makes more sense to send single requests if the ids have different types.

Before we can get to the RestFB implementation details, we have to explain some fundamentals. Some requests - like a post’s comments or a user’s feed - are returned as a list. Because these lists can be very large, Facebook provides a paging mechanism. This means you receive only a limited amount of items encapsulated in a single JSON response (a “page”). To get access the next page, you have to call a special URL which is provided for you as part of the page data. You can iterate over all pages by calling these urls. The relevant field in the paging JSON is called next.

Every page includes the data you requested - comments, posts, accounts and so on. To access this data, you have to iterate over the list on the page. It is important to mention that there is a limit query parameter. It limits the elements on one page. Changing the limit parameter does not change the overall number of items. You can still iterate over all pages, but you can change the amount of requests needed for this. For example, if you’d like to query for a maximum of 50 posts, you should use a counter and stop both loops as soon as no new items are found or your limit is reached (source code is further below).

RestFB supports paging, but you need to fetch the endpoint with the special FacebookClient.fetchConnection() method. One page of a pageable result set is called a Connection. Now you can iterate over the Connection and you’ll get a lot of lists of the fetched element. The loading of the next list is automatically done by RestFB so you don’t need to know how the URLs are built.

Use fields to change the configuration of the returned objects

Fetching lists of objects supports this technique to specify which fields should be returned. To get better insight how the fields parameter can be used, check out the Advanced Usage section.

A common use case is to fetch all elements of a specific endpoint and work with those items. You can manage this by nested iteration. So you iterate over the connections and iterate over the list in one connection. This sounds a bit complicated, but the following source code example shows how it works.

Connection<Post> myFeed = facebookClient.fetchConnection("me/feed", Post.class);
// Connections support paging and are iterable

// Iterate over the feed to access the particular pages
for (List<Post> myFeedPage : myFeed) {

  // Iterate over the list of contained data 
  // to access the individual object
  for (Post post : myFeedPage) {
    out.println("Post: " + post);
  }
}

The Connection object implements the Iterable interface. With this interface it is possible to get an iterator object or you can simply use the foreach loop as you can see in the code example above.

We already mentioned the limit parameter and in the following example we show how to use it and how you can use a personal limit.

String postId = "12345"
Connection<Comment> commentConnection 
   = facebookClient.fetchConnection(postId + "/comments", 
         Comment.class, Parameter.with("limit", 10));

int personalLimit = 50;

for (List<Comment> commentPage : commentConnection) {
  for (Comment comment : commentPage) {
    out.println("Id: " + comment.getId());
    personalLimit--;

    // break both loops
    if (personalLimit == 0) {
       return;
    }
  }
}

In some rare cases you may need to prevent RestFB from automatically loading further results and exert deeper control over what the Connection object is doing. To do this, you must not use the normal iteration process and use a different approach instead. You can simply work with the very common iterator pattern as mentioned above. Or you can use the Connection.hasNext() and Connection.next() methods on a connection object. Together with the Connection.getData() you have complete control over the object.

We don't suggest using this, ...

... because it makes the complete process of fetching items from Facebook unnecessarily complicated and error-prone. Nevertheless, here is a short example of how to use the more complicated way to duplicate the functionality of the first code example in this section.

Connection<Post> myFeed = facebookClient.fetchConnection("me/feed", Post.class);
	
// Get the iterator 
Iterator<List<Post>> it = myFeed.iterator();

while(it.hasNext()) {
   List<Post> myFeedPage = it.next();
	   
   // This is the same functionality as the example above
   for (Post post : myFeedPage) {
     out.println("Post: " + post);
   }
}
// Fetching Insights data is as simple as fetching a Connection

Connection<Insight> insights = 
	facebookClient.fetchConnection("PAGE_ID/insights", Insight.class);

for (Insight insight : insights.getData())
  out.println(insight.getName());

Fetching objects with RestFB is straightforward, but there’s a special endpoint that is a bit different and can be a little confusing.

If you call the <userid>/picture endpoint you don’t receive a JSON response object. This endpoint redirects directly to the user picture and you get the image’s binary data.

GET https://graph.facebook.com/v2.5/me/picture

The GET request above returns these header fields.

status: 302
content-type: image/jpeg
pragma: no-cache
location: https://example.fbcdn.net/example_profile_picture.jpg

Now, we want to receive the image url in a JSON instead of the binary data. This can be achieved by adding a special parameter to the request URL. The query parameter is redirect=false.

The corresponding Java code looks like this:

FacebookClient client = new DefaultFacebookClient(accessToken, Version.LATEST);
JsonObject picture = 
      client.fetchObject("me/picture", 
	      JsonObject.class, Parameter.with("redirect","false"));

With this “trick” you receive a JSON response as expected when calling the Facebook Graph endpoint.

{
  "data": {
    "is_silhouette": false,
    "url": "https://example.fbcdn.net/example_profile_picture.jpg"
  }
}

Logging

Before we go further, a few words about logging...

RestFB uses java.util.logging to log the data that's sent over the wire to and from Facebook. It's often helpful to look at the log output so you can make sure that RestFB is sending the data as you expect it to and that Facebook is returning the correct JSON.

Want to use Log4j instead of java.util.logging? No problem! You can disable java.util.logging for RestFB and use SLF4J to re-route (bridge) all logging calls to Log4j. You may look at our example project which demonstrates this process</a>.

If you're curious about how this works, here's more information about SLF4J bridging.

If you're concerned about SLF4J bridging performance, check out this section of the SLF4J manual.
Thanks to Chris Pruett for the heads-up about that.

RestFB uses java.util.logging as its logging framework. But many applications are based on slf4j. slf4j provides a bridge to log java.util.logging via slf4j. The following example shows how this can be done.

// You'll want to initialize the bridge just once at app startup.
// In a webapp, a good place to do this is ContextLoaderListener#contextInitialized()
SLF4JBridgeHandler.install();

try {
  FacebookClient facebookClient = new DefaultFacebookClient();

  // You'll notice that logging statements from this call are bridged from java.util.logging to Log4j
  User user = facebookClient.fetchObject("btaylor", User.class);

  // ...and of course this goes straight to Log4j
  logger.debug(user);
} finally {
  // Make sure to tear down when you're done using the bridge.
  // In a webapp, a good place to do this is at Servlet Container shutdown time
  SLF4JBridgeHandler.uninstall();
}

To make the configuration of our logging more easy for developers, we don’t use loggers that are initialized with the name of the class they are created in. Our loggers have fixed names and the therefore the logging is clustered into categories.

In the RestFB version 1.x line we named the categories after the former class names so we don’t break current logging configurations. With the next major update this will change.

com.restfb.HTTP

The HTTP logger is used to keep track of the communication between RestFB and the Facebook Graph API. In the log file you'll find the requests/responses, header information and more.

com.restfb.DefaultJsonMapper

The JsonMapper is used to convert JSON to RestFB types. Because the conversion contains many interesting steps, we provide a special logger. If everything works as is should the logger is very silent, but the developer may change the log level to DEBUG or TRACE to get much more information about what’s going on during the mapping process. You should do this only if you run into problems and would like to track them down to a special conversion step.

com.restfb.UTILITY

The logger is used in our utilities. We have utilities for date conversion, base64 calculations and more. Just check the com.restfb.util package. These utilities log some information and use this special logger to not pollute the other logs with less important information.

com.restfb.DefaultFacebookClient

This logger provides information about the communication between the application and RestFB.

com.restfb.types.webhook.ChangeValueFactory

The log messages in the ChangeValueFactory are used to notify the developer about some problems with the conversion of a object that is received via a webhook. Maybe RestFB does not support this special value object and the developer can capture the log output to send a special String to the RestFB team. Because this is different from the normal logging, we provide a special logger and the developer may filter these messages and log them in a different log file.

As you can see, all loggers use the package structure with the prefix com.restfb.. With this it is possible to change the log level of all loggers at once.

# Example logging.properties entries
# ==================================

# to log the call to facebook including their responses
# you can change the com.restfb.HTTP log level accordingly during development time
com.restfb.HTTP.level=ALL

# the complete restfb package logging can be configured like this
com.restfb.level=WARNING

Searching

With RestFB it is very easy to search Facebook. But before we go deeper in this topic, you need to know some basic information. First, Facebook differentiates between the public search and the targeted search. With the public search, you can search for public information and get some useful insights in what’s going on at Facebook. The targeted search is another approach to filter your private information.

The public search uses a special endpoint called search. You have to provide a query string (q) and a type parameter (type). With this technique, you’ll get back data that can be marshaled to the normal RestFB types. For example, you might search for a user with the name “Mark” and get back a List of User objects. Because you receive a List, you have to use the Connection pattern RestFB provides.

Public search for posts is no longer supported

With Graph API 2.0, Facebook discontinued support for the search type `Post`. As a result, you can no longer search for user posts. Be careful - some old tutorials are not updated yet!

The supported public search types are user, page, event, group, place, placetopic and ad_*. Some types like place need additional parameters so you should have a look at the Facebook Graph API Search documentation.

// Searching is just a special case of fetching Connections -
// all you have to do is pass along a few extra parameters.

Connection<User> publicSearch =
  facebookClient.fetchConnection("search", User.class,
    Parameter.with("q", "Mark"), Parameter.with("type", "user"));

With “targeted search” you are able to search in a user’s home, a.k.a. news feed. You can simply call the /me/home endpoint and add the q parameter as mentioned in the sections above.

Connection<User> targetedSearch =
  facebookClient.fetchConnection("me/home", User.class,
    Parameter.with("q", "Mark"), Parameter.with("type", "user"));

out.println("Posts on my wall by friends named Mark: " + targetedSearch.getData().size());

Using FQL

See FQL documentation

FQL is deprecated and removed with Graph API 2.1

With Graph API 2.1, Facebook discontinued support for FQL (Facebook Query Language). All applications using Graph 2.1 or newer need to change their request and should work with the Graph API.

Because not every kind of request can transferred to Graph API, you should have a look at the Webhooks (former Real-Time Updates).

We support Webhooks with special types and you should look at the Webhooks section in this documentation.

On August 7, 2016 Facebook discontinued support for both Graph API 2.0 and FQL.

Using Webhooks

The Graph API has supported real time updates for a long time and with Graph API 2.2 the real time updates for pages have been improved a lot. Since, Graph API 2.5 the real time updates (RTU) have been renamed and are now called Webhooks.

Webhooks replace the polling mechanism with a pushing solution. With the deprecation of the FQL API, this is the only way to get notification about changes in a news feed and other Facebook objects. These changes are very lightweight and that’s the reason why you only get some basic information. But you receive everything that is important and may fill missing information with a normal Graph API call.

Technically you have to provide an endpoint on a server that is reachable by Facebook and understands the JSON-formatted POST requests received from Facebook. You may simply parse them with a JSON library or you can use the new Webhook types from RestFB.

To get a much deeper insight and a better overview you should take a look at the Facebook explanation of Webhooks.

The Webhook types in RestFB are a very special construction. They are fetched differently from other types and while they appear similar on the surface, their internals are completely different. The JSON is pushed to your server and so you cannot use the normal fetchObject method. You have simply a JSON String and you can now use a JsonMapper to convert it to a Java object.

The result is a Webhook entity and you only need to call something like this:

String pushedJsonAsString; // It's up to you to fill this String
JsonMapper mapper = new DefaultJsonMapper();
WebhookObject webhookObject = 
         mapper.toJavaObject(pushedJsonAsString, WebhookObject.class);

Now you can step through the WebhookObject and fetch the necessary information. The structure is a bit cumbersome, but RestFB has to reflect the original Facebook JSON structure. In this way, we are able to react to changes much faster and are able to expand our Webhooks support as new possibilities arrive.

The value-field of the Change object is very interesting. Here we added a new solution and made use of the @JsonMappingCompleted annotation in combination with a ChangeValueFactory.

Because the difference between the WebhookObjects you receive from Facebook lies in the change value, we implemented a factory so you can work with the correct entity and don’t need to implement some logic. Because some change values contain a postId, some a photo URL and other specific differences. These are provided by a group of classes whose names end with Value.

Important notice regarding the new Webhook types

At the moment we only support a subset of all possible webhook JSON types. The main focus lies on the page webhooks. You should be able to use the Webhooks nevertheless, but perhaps you have to deal with the FallBackChangeValue. It encapsulates the raw JSON that represents the change value and you may work with the JSONObject, but it lacks some convenience methods.

If this happens, you will see a log message with a hint to send us the JSON. We would really like to implement more Value classes and with the help of our users and the RestFB community we can provide a complete solution for Webhooks.

Messenger Platform

See Messenger Platform documentation

With Graph API 2.6, Facebook introduced the Messenger API. The new API allows developers to implement chat bots. With these bots it is possible to provide a great new user experience and the user may contact his/her favorite Facebook pages directly with the messenger.

The implementation of such a bot consists of two elements.

The first element is the webhook. Webhooks are used to receive messages from a user and new JSON requests are sent from Facebook. RestFB supports these new JSON requests and you can find new objects in the webhook packages of the RestFB types. Because the entrypoint to these types is the same as with normal webhooks, you should have a look at the Webhooks section if you need to refresh your knowledge. Otherwise use the webhooks as before and have a short look at the Facebook Messenger Webhook API to understand how they are built.

The second and the more interesting part of the Messenger API is the Send API. After receiving a text from a user, your bot should react to the request and you can now have different possibilities to respond. The different types are covered in the following sections, but you have first to know how the Send API is used and how RestFB supports you with the Send API.

Sending a message to a user requires a unique recipient identifier. There are two types of identifiers that are supported by the Send API.

The first is the id-identifier. You can get the recipient id as soon as a user sends a message to your bot. Please be aware of the fact that the recipient id is not the user id. If you try to send a message to a user id this will not work. You are required to use the recipient id.

If you received a message and took the id from that message you can create a new IdMessageRecipient with this simple line of code:

IdMessageRecipient recipient = new IdMessageRecipient("<userID>");

The second identifier type is the phone number of the user you try to contact. Facebook only sends a message to a phone number if there is a certain level of confidence the the phone number can be reached.

PhoneMessageRecipient recipient = new PhoneMessageRecipient("<userID>");

Now we have a recipient and need something we want to send to the recipient.

The simplest message you can send to a user is the text message. To generate a text message simply need to generate a Message object and use the String constructor.

An example looks like this:

Message simpleTextMessage = new Message("Just a simple text");

A Message object can contain an attachment. A simple attachment is the MediaAttachment and you only need to provide a URL that points to the attachment and the type of it. Available types are IMAGE, VIDEO, AUDIO and FILE.

The attachment is then added to the newly-created message. The Message is created like this:

MediaAttachment image = 
     new MediaAttachment(MediaAttachment.Type.IMAGE, "http://example.com/testimage.jpg");
Message imageMessage = new Message(image);

Facebook allows more complex objects and with these it is possible to define postbacks the user can use.

The postback is a button that is presented to the user in the messenger. On click, a specially-defined string is sent back to the bot via the webhook api so the bot knows which button was pressed.

Like the postback button, there exists a WebButton. A click on that button directs the user to a webpage.

In this example we create both types of buttons and add them to a Message.

ButtonTemplatePayload payload = new ButtonTemplatePayload("TEMPLATE TITLE");

// build a new button that links to a web url
WebButton webButton = new WebButton("EXAMPLE TITLE", "http://example.org/sample.html");

// build a button that sends a postback
PostbackButton postbackButton = new PostbackButton("EXAMPLE TITLE", "POSTBACK_STRING");

payload.addButton(webButton);
payload.addButton(postbackButton);

TemplateAttachment templateAttachment = new TemplateAttachment(payload);
Message imageMessage = new Message(templateAttachment);

A more complex example is the “generic” template.

It may contain some of the so-called “bubbles” that are horizontally-aligned and the user can switch between them. Switching between bubbles is performed by clicking on a arrow at the left or at the right side of the messenger view. Devices with touch support like smartphones can switch between these bubbles by swiping them to the left or right. The arrows are only visible on mouseover, so you should not be confused if you add more than one bubble and don’t see the other bubbles at first glance.

Every Bubble can contain further information like subtitles and images as well as the buttons we already saw in the earlier example.

The GenericTemplate allows a developer to create great-looking messages users can interact with in very new ways.

GenericTemplatePayload payload = new GenericTemplatePayload();

// Create a bubble with a web button
Bubble firstBubble = new Bubble("Title of first bubble");
WebButton webButton = new WebButton("EXAMPLE TITLE", "http://example.org/sample.html");
firstBubble.addButton(webButton);

// Create a bubble with a postback button
Bubble secondBubble = new Bubble("Title of second bubble");
PostbackButton postbackButton = new PostbackButton("EXAMPLE TITLE", "POSTBACK_STRING");
secondBubble.addButton(postbackButton);

payload.add(firstBubble);
payload.add(secondBubble);

TemplateAttachment templateAttachment = new TemplateAttachment(payload);
Message imageMessage = new Message(templateAttachment);

Now, we are ready to do the most important thing with our new build objects: sending them to Facebook.

We use the well known publish method of RestFB and only need to use the right endpoint with the right access token.

To send the message you have to use two parameters, the recipient and the message.

So we are ready to go and do something like this:

// the access token can be found in your Facebook app in the messenger section
String pageAccessToken = "MY PAGE ACCESS TOKEN";

// create a version 2.6 client
FacebookClient pageClient = new DefaultFacebookClient(pageAccessToken, Version.VERSION_2_6);

SendResponse resp = pageclient.publish("me/messages", SendResponse.class,
     Parameter.with("recipient", recipient), // the id or phone recipient
	 Parameter.with("message", message)); // one of the messages from above

A special use case for the new messages is the welcome message. You can set a special message on a page that is sent as soon as a new user starts a conversation with your page.

This welcome message contains three parameters: setting_type, thread_state and call_to_actions.

Facebook expects that setting_type and thread_state are used as they are defined in the documentation and you should not modify them. Only call_to_actions is a parameter that you have to change to modify the welcome message. It’s a list of messages and these messages may be created as explained in the chapters above.

Now we dive into coding. We configure a welcome message and send it to Facebook.

First we have to create some Parameter objects.

Parameter settingType = Parameter.with("setting_type", "call_to_actions");
Parameter threadState = Parameter.with("thread_state", "new_thread");

Now a message object is created and added to our convenience object CallToAction to make the process a bit easier. In our example we only create a simple text message, but it’s possible to create more complicated objects.

Message simpleTextMessage = new Message("Welcome and chat with the Testbot");
CallToAction welcome = new CallToAction(simpleTextMessage);

List<CallToAction> actionList = new ArrayList<CallToAction>();
actionList.add(welcome);

After creating all the objects we can wire everything together and send it to Facebook.

// we assume there's already a FacebookClient
JsonObject response = client.publish("<pageid>/thread_settings", 
     JsonObject.class, // the returned result as JsonObject
     settingType, // the setting type
     threadState, // the thread state
     Parameter.with("call_to_actions", actionList)); // our simple text message

If the request was successful you can check the result JSON and it looks like:

{
    "result": "Successfully added new_thread's CTAs"
}

Sometimes you need to send a large text to a recipient. Using the messenger platform this can be done in a very small amount of time. Because this is not a natural behavior for a normal user, it is possible to simulate typing so you let the user think she is talking to a human being.

RestFB supports this with a special enum called SenderActionEnum. In the following example, you can see how the typing simulation can be started.

IdMessageRecipient recipient = new IdMessageRecipient("<userID>");
Parameter senderActionParam = Parameter.with("sender_action", SenderActionEnum.typing_on);
Parameter recipientParam = Parameter.with("recipient", recipient);
SendResponse resp = pageclient.publish("me/messages", SendResponse.class,
     senderActionParam, // the sender action
     recipientParam); // the recipient

To stop the typing you can simply use the SenderActionEnum.typing_off instead.

The SenderActionEnum.mark_seen action is very interesting. With this, you are able to show the recipient that you’ve read his/her message. This is useful to give the user a good experience and the feeling he/she is talking to a human although it is a bot.

Since March 2, 2017 there is a new persistent menu available. The new menu can contain sub menus and allows the developer to forbid a user interaction by text input. The user may only select items in the menu and the bot does not need to understand entered text. It seems Facebook tries to support bots that are “dumb”, because these bots cannot react in a useful way to arbitrary text inputs. More sophisticated bots have to understand the text input and act to the input in a way that makes sense.

Back to the persistent menu: The menu can contains several kinds of items. These can be discoverd by checking the MenuItem marker interface. A new item type is the NestedButton. This is the access to the submenu and the NestedButton can contain a list of call-to-actions.

At the moment only hierarchy is limited to 3 levels and on a level 5 actions are allowed.

Very important is the localization feature. A developer can decide, depending on the user’s language, what kind of menu a bot shows and if the text input is supported or not.

The following code example is from the Facebook documentation and has been adapted to RestFB and the persistent menu structure. With this you are able to compare the JSON with the object oriented approach RestFB provides.

The menu is shown as soon as the user has the en_us language selected. Then we disable the text input and show 2 buttons, a WebButton and a NestedButton. The Nestedbutton (“My Account”) is the access point to the underlaying submenu with some “account details”. Some PostbackButtons are used to let the user decide what she/he wants to do next: “Pay Bill”, “History” or “Contact Info”.

PersistentMenu menu = new PersistentMenu("en_us");
menu.setComposerInputDisabled(true);

WebButton webUrl = new WebButton("Latest News", "http://petershats.parseapp.com/hat-news");
webUrl.setWebviewHeightRatio(WebviewHeightEnum.full);

NestedButton nested = new NestedButton("My Account");
nested.addCallToAction(new PostbackButton("Pay Bill", "PAYBILL_PAYLOAD"));
nested.addCallToAction(new PostbackButton("History", "HISTORY_PAYLOAD"));
nested.addCallToAction(new PostbackButton("Contact Info", "CONTACT_INFO_PAYLOAD"));

menu.addCallToAction(nested);
menu.addCallToAction(webUrl);

With these new objects it is possible to build great persistent menus and the locale feature allows a more advanced interaction with the user.

Facebook does not allow unlimited data to be sent via the Send API and therefore they limit the amount of some fields. RestFB does not limit the data, because they may change in the future and so you don’t have to wait for new relases to use the new limits.

Limitations while creating new messages

  • Titles may have up to 45 charactes
  • Subtitles may have up to 80 charactes
  • Call-to-action titles may have up to 20 characters
  • Call-to-action items may have up to 3 buttons
  • A message may have up to 10 bubbles

Advanced Usage

See Graph API documentation

The Facebook Graph API provides a great feature which permits deep insight into node data. This feature is called introspection and it works similarly to the well-known reflection techniques that are part of many programming languages.

To activate introspection, you simply need to add the metadata parameter with the value 1. How this is done can be found in the Passing Parameters section or look at the example at the bottom of this section.

RestFB supports ths feature, too. All types that extend the FacebookType have access to the metadata and you simply need to call the getMetadata method. The returned Metadata contains all the fields, connections and the type of the requested object.

The type is very important if you don’t know what kind of node an id represents. In this metadata field you’ll find the node and you can use this information to send a more complex and type-dependent request to Facebook. For example, if you analyze a feed and its from fields, it is important to discriminate based on type because the from may contain a User or a Page.

// You can specify metadata=1 for many calls, not just this one.
// See the Facebook Graph API documentation for more details.

User userWithMetadata =
  facebookClient.fetchObject("me", User.class, Parameter.with("metadata", 1));

out.println("User metadata: has albums? "
  + userWithMetadata.getMetadata().getConnections().hasAlbums());

See Graph API documentation

Some requests need additional parameters. With Graph API 2.4 for example it is mandatory to provide the fields parameter to get a more extensive response. RestFB provides the Parameter class to serve this purpose.

The Parameter class needs a name and a value to be sent to Facebook. The value is internally processed by a json mapper, so you can provide a JsonObject, a primitive java type (like String, Boolean and so on), or a class that uses the @Facebook annotation (for example the RestFB types or custom ones).

// You can pass along any parameters you'd like to the Facebook endpoint.

Date oneWeekAgo = new Date(currentTimeMillis() - 1000L * 60L * 60L * 24L * 7L);

Connection<Post> filteredFeed = facebookClient.fetchConnection("me/feed", Post.class,
  Parameter.with("limit", 3), Parameter.with("until", "yesterday"),
    Parameter.with("since", oneWeekAgo));

out.println("Filtered feed count: " + filteredFeed.getData().size());

See Graph API documentation

If you fetch a type from Facebook you get a prefilled version. With Graph API 2.4 Facebook changed the behavior and you get only a very minimalistic object. The basic idea of this approach is to save bandwidth and make the transfer much faster, but you have to tell Facebook which fields you need. The requested fields have to be provided as comma separated list.

Basically you should add the fields parameter on every request. So you can be sure to get the right information. The fields a type supports can be found in the Graph API Reference.

Request with fields (first level)

A simple example looks like the following snippet. A user is fetched with id, name and email field filled.

// fetch user type with id, name and email prefilled
User user = facebookClient.fetchObject("me", User.class,
     Parameter.with("fields", "id,name,email")); 

out.println("User name: " + user.getName());

Request with fields (limit)

A even more interesting feature is the limit(x) method. If a type contains a field that represents a list of other types, for example the comments field on a post, you can limit the transferred objects with the limit(). This sounds very complicated and abstract but is very easy to use. To show the usage we have a simple example.

// fetch post type with from, to and two comments prefilled
Post post = facebookClient.fetchObject("74133697733_10152424266332734", Post.class,
     Parameter.with("fields", "from,tp,comments.limit(2)"));

Request with fields (second level)

Now we go a step further and have a look at the second level of the fields. Until now we worked only with the first level, but Facebook supports more levels. In this example we use the second level. The next level is added with the curly brackets and they encapsulate the fields of the next level type. This sounds complicated too, but is easy as soon as you see a example. And here we go:

// fetch post type with from, to and two comments prefilled,
// the comments contain only the from and message fields
Post post = facebookClient.fetchObject("74133697733_10152424266332734", Post.class,
     Parameter.with("fields", "comments.limit(2){from,message}"));

Request with fields (third to n-th level)

And the last example is the third level. Now we take the last example and request only the id from the from field. This is similar to the second level and so you get a idea how the different levels work and so you can work with n-levels if necessary.

// fetch post type with from, to and two comments prefilled,
// the comments contain only the from and message fields
// the inner from field contains only the id
Post post = facebookClient.fetchObject("74133697733_10152424266332734", Post.class,
     Parameter.with("fields", "comments.limit(2){from{id},message}"));

see July 2013 Breaking Changes

To fetch the likes, shares and comments count you must use the correct parameters, because Facebook does not sends you this information with a normal call. In the example at the bottom all fields (shares, comments and likes) are fetched and you see how easy it is to fetch these information with RestFB.

You need to know how the parameters work so we dive a bit in this speciality. As soon as you request one of the three candidates you get a short list and you can page through the results, but you don’t get a complete overview. As soon as you add the summary(true) part - don’t forget the dot delimiter - you get additional fields from Facebook with interesting information. The most important information is the total count. RestFB wraps the summary in the Comments, Shares and Likes type and e.g. the Post type has the special methods getLikesCount, getSharesCount and getCommentsCount that use the summary.

This explains why you need to add the fields parameters to the request, otherwise the method returns the fallback value 0;

As you can see there is a limit(0) part added to the request. This is simply used to reduce the transferred data. Because no share, comment or like is transfered and only the summary is present. We should support Facebook and don’t request data we don’t use.

// Some Post from the GoT Fanpage with likes and comments total count
Post post = client.fetchObject("74133697733_10152424266332734",
  Post.class,
  Parameter.with("fields", "from,to,likes.limit(0).summary(true),comments.limit(0).summary(true),shares.limit(0).summary(true)"));

out.println("Likes count: " + post.getLikesCount());
out.println("Shares count: " + post.getSharesCount());
out.println("Comments count: " + post.getCommentsCount());

Creating JSON Objects

Getting Any Kind of Data as a JSON Object

Sometimes you can’t know field names at compile time so the @Facebook annotation can’t be used. Or maybe you’d like full control over the data that gets returned. Either way, RestFB has you covered. Just map any API call to JsonObject.

JsonObject is the lowest-level object type. You have full control over the object, but you don’t have convenient type mapping support available. For example, date fields are just Strings and you have to map them manually to a Date object. The version independence regarding the Graph API is gone, too. You should only work with the JsonObject if you know what you are doing.

Fetching a single object is almost the same as with a standard RestFB type. You simply choose the JsonObject as returned type and you are ready to go. Afterwards you can use the JsonObject API.

The JsonObject API depends on the used RestFB version

In RestFB 1.x we use the reference implementation that is provided by json.org. Our JsonObject API is therefore the same as in that library.

With RestFB 2.x the internally-used JsonObject implementation changed and is based on the minimal-json library. In our benchmarks, this implementation is much faster. When migrating from RestFB 1.x to 2.x, you must modify your code to support this API change if you are using the low-level JsonObject in your project.

JsonObject btaylor = facebookClient.fetchObject("btaylor", JsonObject.class);

out.println(btaylor.getString("name"));

If you’d like to use a JsonObject in a Connection, there are two ways you can go. The first was is to simply use the JsonObject as the returned type and work with fetchConnection as described in the Fetching Object List section.

JsonObject photosConnection = facebookClient.fetchConnection("me/photos", JsonObject.class);

for (List<JsonObject> objectList: photosConnection) {
   for (JsonObject photo: objectList) {
       String photoUrl = photo.getString("source");
       out.println(photoUrl);
   }
}

The second way is even more low-level and you work only with the JSON returned by Facebook. You should have a good knowledge of the returned JSON to access the fields. In the below example you can see how to accomplish this:

JsonObject photosConnection = facebookClient.fetchObject("me/photos", JsonObject.class);

String firstPhotoUrl = photosConnection.getJsonArray("data").getJsonObject(0).getString("source");
out.println(firstPhotoUrl);

Using the low-level JsonObject is sometimes OK, but perhaps you’d like to map the object or special fields to RestFB types. You can manually invoke the built-in JsonMapper to do this.

List<String> ids = new ArrayList<String>();
ids.add("btaylor");
ids.add("http://www.imdb.com/title/tt0117500/");

// First, make the API call...

JsonObject results = facebookClient.fetchObjects(ids, JsonObject.class);

// ...then pull out raw JSON data and map each type "by hand".
// Normally your FacebookClient uses a JsonMapper internally, but
// there's nothing stopping you from using it too!

JsonMapper jsonMapper = new DefaultJsonMapper();
User user = jsonMapper.toJavaObject(results.getString("btaylor"), User.class);
Url url = jsonMapper.toJavaObject(results.getString("http://restfb.com"), Url.class);

out.println("User is " + user);
out.println("URL is " + url);

Publishing

See Graph API documentation

// Publishing a simple message.
// GraphResponse represents any Facebook Graph response that has an ID property.
// The GraphResponse type supports the optional post_id field

GraphResponse publishMessageResponse =
  facebookClient.publish("me/feed", GraphResponse.class,
    Parameter.with("message", "RestFB test"));

out.println("Published message ID: " + publishMessageResponse.getId());

// Publishing an event

Date tomorrow = new Date(currentTimeMillis() + 1000L * 60L * 60L * 24L);
Date twoDaysFromNow = new Date(currentTimeMillis() + 1000L * 60L * 60L * 48L);

GraphResponse publishEventResponse = facebookClient.publish("me/events", GraphResponse.class,
  Parameter.with("name", "Party"), Parameter.with("start_time", tomorrow),
    Parameter.with("end_time", twoDaysFromNow));

out.println("Published event ID: " + publishEventResponse.getId());

See Graph API documentation

Publishing a photo is an example of publishing binary content. There are two ways to publish binary content to Facebook. The old and deprecated way is with an InputStream and the new way with a ByteArray. Although the InputStream method is deprecated you may use it and we don’t intend to remove it in the near future.

You may use some endpoints to publish a photo and it depends on your usecase which one you have to use. It is important to use the correct access token, because some endpoints have specific permission requirements.

Note regarding publishing multiple photos at once

Publishing multiple photos simple does NOT work. Directly from the Facebook Graph API documentation:

"There is no way to publish more then one photo in the same graph API call."

(see here at creating section)

The first example shows the InputStream. In addition to the binary content a message is added in the first case and a description in the second one.

// Publishing an image to a photo album is easy!
// Just specify the image you'd like to upload and RestFB will handle it from there.

GraphResponse publishPhotoResponse = facebookClient.publish("me/photos", GraphResponse.class,
  BinaryAttachment.with("cat.png", getClass().getResourceAsStream("/cat.png")),
  Parameter.with("message", "Test cat"));

out.println("Published photo ID: " + publishPhotoResponse.getId());

// Publishing a video works the same way.

facebookClient.publish("me/videos", GraphResponse.class,
  BinaryAttachment.with("cat.mov", getClass().getResourceAsStream("/cat.mov")),
  Parameter.with("description", "Test cat"));

This second example shows how to use a BinaryAttachment with a byte array. The generation of the array is not part of the example code, because it is highly dependent on the libraries used in your project and the way you receive the binary content.

byte[] imageAsBytes = fetchBytesFromImage();
DefaultFacebookClient client =
	new DefaultFacebookClient(getTestSettings().getPageAccessToken(), Version.VERSION_2_4);
JsonObject obj = client.publish(getTestSettings().getPageId() + "/feed", JsonObject.class,
	BinaryAttachment.with("test.png", imageAsBytes, "image/png"), Parameter.with("message", "TestImage"));

In the previous section focused on publishing a photo. Now we expand on this a bit and include a Tag as part of the publishing process. A tag permits you to link a Facebook user to a photo, providing formal information about who is in the photo.

To tag a user you need two things. First, a custom PhotoTag type, and second, you have to modify the request from the previous section. Because the custom type is the most important and exciting thing, we start with the custom type.

public class MyPhotoTag {
   @Facebook("tag_uid")
   private String tagUid;

   @Facebook("tag_text")
   private String tagText;

   @Facebook
   private Double x;

   @Facebook
   private Double y;

   // add getter and setter here
}

Now we have the custom type and may create a new instance. This is just good old Java. Now, let’s get to the publishing part. To make it easier, we use the publish call from the previous section and simply add the new parameter. When everything is wired together it looks like this:

byte[] imageAsBytes = fetchBytesFromImage();
MyPhotoTag myTag = new MyPhotoTag();
// fill myTag here
ArrayList<MyPhotoTag> myTagList = new ArrayList<MyPhotoTag>();
myTagList.add(myTag);
DefaultFacebookClient client =
	new DefaultFacebookClient(getTestSettings().getPageAccessToken(), Version.LATEST);
JsonObject obj = client.publish(getTestSettings().getPageId() + "/feed", JsonObject.class,
	BinaryAttachment.with("test.png", imageAsBytes, "image/png"),
	Parameter.with("message", "TestImage"),
	Parameter.with("tags", myTagList));

We use the list in this example because Facebook allows up to 40 tags per photo.

See Graph API documentation

Publishing a checkin works like publishing a normal post to a user’s feed. You simply have to provide a place parameter with a place id. If you only have longitude and latitude, you have to search for places in the given area first and let the user select the correct place. Publishing via longitude/latitude is not possible since Graph API version 2.0. (see Stackoverflow question)

GraphResponse publishCheckinResponse = facebookClient.publish("me/feed",
  GraphResponse.class, Parameter.with("message", "I'm here!"),
    Parameter.with("place", 1234)));

out.println("Published checkin: " + publishCheckinResponse.getId());

See Graph API documentation

Uploading a short video is the same as uploading a picture. You should take a look at the picture section to understand how it works.

A new feature Facebook added with Graph API 2.4 is resumable upload support. Large videos (up to a file size of about 2GB) should be uploaded with this new approach. The current max value can be found in the Graph API documentation, or you can simply try to start the upload and handle any filesize errors that occur.

The resumable upload is divided in 3 phases: Start, Transfer, and Finish. If you are familiar with databases and transactions, you can compare the start with starting a transaction and finish with committing it. The transfer phase is where the real action takes place.

The Start Phase

The first phase is the Start phase. Instead of uploading the file itself, you tell Facebook you want to upload a file and how big it is. The file size you send to Facebook is in bytes. Facebook checks the size and returns an error if something is not okay, but normally you should get a Video ID, a Session ID, and the range of bytes (expressed as a start and end offset) Facebook expects you to send in the first transfer chunk.

File videoFile = new File(uploadableFile.getFile());
long filesizeInBytes = videoFile.length();
// We need the file size in bytes to make the start request
FacebookClient fbc = new DefaultFacebookClient(accessToken, Version.LATEST);
ResumableUploadStartResponse returnValue = fbc.publish("PAGE_ID/videos",
     ResumableUploadStartResponse.class, // The return value
     Parameter.with("upload_phase", "start"), // The upload phase
     Parameter.with("file_size", filesizeInBytes)); // The file size

long startOffset = returnValue.getStartOffset();
long endOffset = returnValue.getEndOffset();
Long length = endOffset - startOffset;

// The upload session ID is very important, because Facebook needs
// this ID to identify all the uploads that belong together
String uploadSessionId = returnValue.getUploadSessionId();

The Transfer Phase

From Facebook’s response, you’ll know what the first chunk of the file you need to upload is. Now you enter the Transfer phase. You upload a chunk of the file the same way you normally upload a binary file to Facebook - you simply have to add some additional information about the offset and session so Facebook can join the file correctly.

With each chunk transfer, Facebook will return the next byte range it’s expecting. This happens in a loop. So you upload the next part and get new offsets, and upload those bytes and so on.

// We have to upload the chunks in a loop
while (length > 0) {
     // First copy bytes in byte array
     byte fileBytes[] = new byte[length];
     in.read(fileBytes);

     // Make the request to Facebook
     ResumableUploadTransferResponse filePart = fbc.publish("PAGE_ID/videos",
      // The returned object 
	  ResumableUploadTransferResponse.class,
	  // The file chunk that should be uploaded now
	  BinaryAttachment.with("video_file_chunk", fileBytes),
	  // Tell Facebook that we are in the transfer phase now 
	  Parameter.with("upload_phase", "transfer"),
	  // The offset the file chunk starts
	  Parameter.with("start_offset", startOffset),
	  // The important session ID of this file transfer
          Parameter.with("upload_session_id", uploadSessionId));

     // After uploading the chunk we recalculate the offsets according to the 
     // information provided by Facebook
     startOffset = filePart.getStartOffset();
     endOffset = filePart.getEndOffset();
     length = endOffset - startOffset;
}

At some point you’ll receive a response where start and end byte offsets are equal. This signifies that it’s time to enter the Finish phase.

The Finish Phase

After uploading all binary chunks you enter the third phase and send Facebook the request to publish the video. The response is the frequently-used “success” JSON and you may use the GraphResponse type to easily access the success field.

GraphResponse finishResponse = fbc.publish("PAGE_ID/videos",
     GraphResponse.class,
     Parameter.with("upload_phase", "finish"), // Tell Facebook to finish the upload
     Parameter.with("upload_session_id", uploadSessionId)); // The corresponding session ID

After you receive a success response, you’ll have to wait until Facebook finishes processing the video. This might take a few minutes. Once done, you’ll receive one or more notifications: an email, a Facebook message, and - if you have a working real time update subscription - a call regarding the new video.

Once you receive a notification, the video is online and ready to be played.

Deleting

See Graph API documentation

To delete an object on Facebook, RestFB provides a deleteObject-method. You have to provide the ID of the object and RestFB does the magic. As a return value you receive a boolean - true means the object had been deleted, false otherwise. You might encounter one of the common exceptions if something happened.

Boolean deleted = facebookClient.deleteObject("some object ID");
out.println("Deleted object? " + deleted);

Batch API

See Graph API documentation

// The Batch API is great if you have multiple operations you'd like to
// perform in one server trip. Let's build a batch with three GET requests and
// one POST request here:

BatchRequest meRequest = new BatchRequestBuilder("me").build();
BatchRequest badRequest = new BatchRequestBuilder("this-is-a-bad-request/xxx").build();
BatchRequest m83musicRequest = new BatchRequestBuilder("m83music/feed")
  .parameters(Parameter.with("limit", 5)).build();
BatchRequest postRequest = new BatchRequestBuilder("me/feed")
  .method("POST")
  .body(Parameter.with("message", "Testing!")).build();

// ...and execute the batch.

List<BatchResponse> batchResponses =
  facebookClient.executeBatch(meRequest, badRequest, m83musicRequest, postRequest);

// Responses are ordered to match up with their corresponding requests.

BatchResponse meResponse = batchResponses.get(0);
BatchResponse badResponse = batchResponses.get(1);
BatchResponse m83musicResponse = batchResponses.get(2);
BatchResponse postResponse = batchResponses.get(3);

// Since batches can have heterogenous response types, it's up to you
// to parse the JSON into Java objects yourself. Luckily RestFB has some built-in
// support to help you with this.

JsonMapper jsonMapper = new DefaultJsonMapper();

// Here we marshal to the built-in User type.

User me = jsonMapper.toJavaObject(meResponse.getBody(), User.class);
out.println(me);

// To detect errors, check the HTTP response code.

if(badResponse.getCode() != 200)
  out.println("Batch request failed: " + badResponse);

// You can pull out connection data...

out.println("M83's feed follows");

Connection<Post> m83musicPosts =
  new Connection<Post>(facebookClient, m83musicResponse.getBody(), Post.class);

for (List<Post> m83musicPostsConnectionPage : m83musicPosts)
  for (Post post : m83musicPostsConnectionPage)
    out.println(post);

// ...or do whatever you'd like with the raw JSON.

out.println(postResponse.getBody());

See Graph API documentation

// Per the FB Batch API documentation, attached_files is a comma-separated list
// of attachment names to include in the API call.
// RestFB will use the filename provided to your BinaryAttachment minus the file
// extension as the name of the attachment.
// For example, "cat-pic.png" must be referenced here as "cat-pic".

List<BatchRequest> batchRequests = Arrays.asList(
  new BatchRequestBuilder("me/photos").attachedFiles("cat-pic").build(),
  new BatchRequestBuilder("me/videos")
    .attachedFiles("cat-vid, cat-vid-2")
    .body(Parameter.with("description", "This cat is hilarious"))
    .build());

// Define the list of attachments to include in the batch.

List<BinaryAttachment> binaryAttachments = Arrays.asList(
  BinaryAttachment.with("cat-pic.png", getClass().getResourceAsStream("/cat-pic.png")),
  BinaryAttachment.with("cat-vid.mov", getClass().getResourceAsStream("/cat-vid.mov")),
  BinaryAttachment.with("cat-vid-2.mov", getClass().getResourceAsStream("/cat-vid-2.mov")));

// Finally, execute the batch.

facebookClient.executeBatch(batchRequests, binaryAttachments);

Access Token Operations

Before you can build your Facebook Login Dialog URL you need to look deeper into the the scope concept. Every Access Token is bound to a scope and a scope is a set of permissions. The developer decides which permissions are needed to get the application working correctly.

RestFB supports the developer building the scope and so you should use the ScopeBuilder. The permissions are implemented as Enums. Here’s an example how to build a scope:

ScopeBuilder scopeBuilder = new ScopeBuilder();
scopeBuilder.addPermission(UserDataPermissions.USER_STATUS);
scopeBuilder.addPermission(UserDataPermissions.USER_ABOUT_ME);

With the ScopeBuilder you can now easily build the login dialog url, like this:

FacebookClient client = new DefaultFacebookClient(Version.VERSION_2_6);
String loginDialogUrlString = client.getLoginDialogUrl(appId, redirectUrl, scopeBuilder);

See Graph API documentation

Normally access tokens are only valid for a short time, but you can extend the lifetime with a simple Facebook call. RestFB provides a method to make this easy.

// Tells Facebook to extend the lifetime of MY_ACCESS_TOKEN.
// Facebook may return the same token or a new one.

AccessToken accessToken =
  new DefaultFacebookClient().obtainExtendedAccessToken(MY_APP_ID,
    MY_APP_SECRET, MY_ACCESS_TOKEN);

out.println("My extended access token: " + accessToken);

See Graph API documentation

App access tokens are used to make server to server calls on behalf of your application. With these special access tokens, you can modify your application settings as well as perform some other calls - for example, publishing Open Graph actions or debugging access tokens.

To obtain an application access token you’ll need your App ID and App Secret. This is the reason why application access tokens are only used in the server-to-server communication.

RestFB provides a mechanism for obtaining app access tokens. You simply have to make the following call:

// Obtains an access token which can be used to perform Graph API operations
// on behalf of an application instead of a user.

AccessToken accessToken =
  new DefaultFacebookClient().obtainAppAccessToken(MY_APP_ID, MY_APP_SECRET);

out.println("My application access token: " + accessToken);

See Graph API documentation

With the Device Access Token Facebook provides a possibility to connect to devices with limited input or display capabilities.

The device access token is generated in a two step way. First you have to call FacebookClient.fetchDeviceCode(see example code). You receive a user code, a code and some additional information. The user code has to be shown to the user and she has to enter it on a special Facebook page. The url of that page is part of the DeviceCode object. You should not hard code this url, because Facebook may changed it. As soon as you presented these information to the user, you have to poll Facebook and try to fetch the device access token.

Fetching with Graph API 2.5 or below

Graph API 2.5 and below don’t use any access token to fetch the device access token. Only the App Id is needed and you are ready to go. First we have receive a DeviceCode object.

// Graph API 2.5 is just an example, you may also use lower versions
DefaultFacebookClient client = new DefaultFacebookClient(Version.VERSION_2_5);
ScopeBuilder scope = new ScopeBuilder();

DeviceCode deviceCode = client.fetchDeviceCode(MY_APP_ID, scope);

out.println("Open in a browser: " + deviceCode.getVerificationUri);
out.println("Enter this Code: " + deviceCode.getUserCode);

Now you have to start the polling of Facebook with the code you received in the DeviceCode object. Every poll request may result in an checked exception that extends the FacebookDeviceTokenException. A table of the possible exceptions and the intention can be found below.

The call that is used to poll the AccessToken from Facebook looks like this. You should call it in a loop:

// Obtains an access token which can be used to perform Graph API operations
// on behalf of a user.

AccessToken accessToken =
   new DefaultFacebookClient().obtainDeviceAccessToken(MY_APP_ID, deviceCode.getCode());

out.println("My device access token: " + accessToken);

Fetching with Graph API 2.6 or newer

With Graph API 2.6 Facebook changed the way a device token is requested. First we need a special access token that consists of the application id and the client token. The client token can be found in the Application Dashboard. The new token looks like <pp_id>|<client_token>. With this access token a new FacebookClient is created and the client is used for the device token interactions with Facebook. Because tha application id is part of the access token we don’t need to provide the application id in the method call. So we have two new methods that work with this access token and don’t use the application id as parameter.

The first part - fetching the DeviceCode - looks like this:

String specialAccessToken = MY_APP_ID + "|" + MY_CLIENT_TOKEN;
// Graph API 2.9 is just an example, you may also use lower versions down to 2.6
DefaultFacebookClient deviceTokenClient = 
         new DefaultFacebookClient(specialAccessToken, Version.VERSION_2_9);
ScopeBuilder scope = new ScopeBuilder();

DeviceCode deviceCode = client.fetchDeviceCode(scope);

out.println("Open in a browser: " + deviceCode.getVerificationUri);
out.println("Enter this Code: " + deviceCode.getUserCode);

Now we have to call the polling call in a loop and can receive the same exceptions as in earlier versions. One change is important: there is no FacebookDeviceTokenDeclinedException because this information is not send to the application. This is a important change, because you have to handle this in your application. You can run into the code expired exception or you let the user close a dialog or something and stop the polling in respect to the user action.

The polling call doesn’t need the application id, so it looks like this:

// Obtains an access token which can be used to perform Graph API operations
// on behalf of a user.

AccessToken accessToken =
   deviceTokenClient.obtainDeviceAccessToken(deviceCode.getCode());

out.println("My device access token: " + accessToken);

The checked device token exception

The polling method should return the AccessToken, but may throw a FacebookDeviceAccessToken exception.

Security Operations

// Facebook can send you an encoded signed request, which is only decodable by you
// with your App Secret. Pass the signed request, your app secret, and a class that
// specifies how RestFB should map the decoded signed request JSON.

String signedRequest = "xxx";
String appSecret = "yyy";
Payload payload = facebookClient.parseSignedRequest(signedRequest,
  appSecret, Payload.class);

out.println("Signed request user_id: " + payload.userId);

// You must write your own class to hold signed request payload data
// since RestFB can't know in advance what fields FB will be sending you.
// Some are always present, like user_id, but the rest will be specific
// to your app and situation.

class Payload {
  @Facebook("user_id")
  String userId;

  @Facebook("oauth_token")
  String oauthToken;

  @Facebook
  Long expires;

  @Facebook("issued_at")
  Long issuedAt;

  Date getExpires() {
    return expires == null ? null : new Date(expires * 1000L);
  }

  Date getIssuedAt() {
    return issuedAt == null ? null : new Date(issuedAt * 1000L);
  }

  // Add whatever other fields you might have
}

A user may uninstall an application in his or her Facebook app settings. Because the application owner might need this information, Facebook calls a Deauthorization Callback. A developer can set the deauthorization callback url in the app settings. As soon as someone uninstalls the app, this url is called with a signed POST request.

RestFB provides support for checking these signed requests and decoding the provided information.

The following snippet explains how to use the DeAuth type to get the user id of the user who uninstalled the app. Additionally, you’ll get the date when the app was uninstalled.

// Facebook can send you an encoded signed request, as soon as someone deletes
// your Facebook app. This only happens if you have defined a deauthorization
// callback url in your Facebook App (Settings -> Advanced).

String signedRequest = "xxx";
String appSecret = "yyy";
DeAuth deauthObj = facebookClient.parseSignedRequest(signedRequest,
  appSecret, DeAuth.class);

out.println("This user just deleted your app: " + deauthObj.getUserId());
out.println("Deauthorization at: " + deauthObj.getIssuedAt());

Most requests need an access token. If someone is able to steal the access token, he or she can send spam with this app.

To make this more secure, Facebook provides a special parameter called appsecret_proof. This is a parameter that is transferred as query parameter in a normal request and contains a hashed version of the app secret. The additional security is only achievable if the communication to Facebook occurs via a server controlled by the developer.

The FacebookClient contains the obtainAppSecretProof method to calculate the proof, but a much easier way is to instantiate the DefaultFacebookClient with the additional appsecret_proof parameter. In that case, the appsecret_proof is automatically added to every call.

// If you create a DefaultFacebookClient instance with your app secret, RestFB will
// automatically include appsecret_proof with your requests,
// no work needs to be done on your end.

FacebookClient facebookClient =
  new DefaultFacebookClient(MY_ACCESS_TOKEN, MY_APP_SECRET, Version.LATEST);

// Request will include appsecret_proof

facebookClient.fetchObject("XXX", User.class);

// You may also generate the appsecret_proof value directly (not normally needed).

String proof = new DefaultFacebookClient().obtainAppSecretProof(
  MY_ACCESS_TOKEN, MY_APP_SECRET);
out.println("Here's my proof: " + proof);

Running The Examples

RestFB provides a repository on Github with an example project. In this repository RestFB is used to fetch several pieces of information from Facebook, publish some information, and run a legacy example. The whole project is Maven-based and you may use this repository to start your own project using RestFB.

To run the examples you need to download the restfb-examples project as zip file or clone it from Github. Don’t forget to replace the MY_ACCESS_TOKEN with your access token, otherwise the examples won’t run.

$ mvn compile
$ mvn exec:java@run-reader-examples -Daccess_token=MY_ACCESS_TOKEN
$ mvn exec:java@run-publisher-examples -Daccess_token=MY_ACCESS_TOKEN
$ mvn exec:java@run-legacy-examples -Daccess_token=MY_ACCESS_TOKEN

Supported Graph Object Types

RestFB can map JSON to any class that has fields annotated with the @Facebook annotation, which is discussed in more detail in the JSON Mapping Rules section.

However, for your convenience, all basic Graph API Object types have their own Java implementation in the com.restfb.types package.

You may use these builtin types if you wish, or you can subclass them to add additional fields or functionality, or just write your own if you have special requirements. The builtins come with reflective implementations of toString(), hashCode(), and equals(Object o) to make your life simpler. If you subclass any of the builtins and add additional fields with accessors, those fields will be automatically taken into account by the above 3 methods.

The builtin types are as follows:

Supported Marketing Types

Since version 1.15.0, RestFB supports the Facebook Marketing API. Because Facebook does not provide a sandbox mode, all types are implemented as defined in the Facebook Marketing API Reference.

The Marketing types are as follows:

JSON Mapping Rules

Using DefaultJsonMapper, RestFB is able to recursively map JSON fields annotated with @Facebook to the following Java types out of the box:

  • The convenience classes provided by RestFB in com.restfb.types
  • String
  • Integer
  • Boolean
  • Long
  • Double
  • Float
  • BigInteger
  • BigDecimal
  • Your own JavaBean-compliant classes
    Don’t forget to provide a public default constructor!
  • Lists of any of the above types

For example:

public class MyClass {
  @Facebook
  String name;

  @Facebook
  BigDecimal value;

  // If a Facebook field doesn't match your field's name, specify it explicitly

  @Facebook("lots_of_numbers")
  List<Integer> lotsOfNumbers;

  // You can annotate methods with @JsonMappingCompleted to perform
  // post-mapping operations.
  //
  // This is useful if you want to massage the data FB returns.

  @JsonMappingCompleted
  void allDone(JsonMapper jsonMapper) {
    if(lotsOfNumbers.size() == 0)
      throw new IllegalStateException("I was expecting more numbers!");
  }
}

Java to JSON mapping is supported by default via JsonMapper.toJson(Object object). You may recursively convert primitive wrapper types as specified above, Lists, Maps with String keys, and your own Javabean types by applying the @Facebook annotation to any fields you’d like to include in the conversion.

The default behavior of DefaultJsonMapper is to throw a FacebookJsonMappingException if it cannot map JSON to Java correctly. However, given the frequency with which the Facebook API changes, you might want to guard yourself from “surprise” errors in production by exerting more fine-grained control over how the mapper handles mapping exceptions. You can do so like this:

FacebookClient facebookClient = new DefaultFacebookClient("MY_ACCESS_TOKEN",
  new DefaultWebRequestor(), new DefaultJsonMapper(new JsonMappingErrorHandler() {
    public boolean handleMappingError(String unmappableJson, Class<?> targetType, Exception e) {

      // Here you might log the fact that JSON mapping failed.

      err.println(format("Uh oh, mapping %s to %s failed...", unmappableJson, targetType));

      // Returning true tells the mapper to map this JSON as null and keep going.
      // Returning false tells the mapper to throw an exception.

      return true;
    }
  }));

As-is, DefaultJsonMapper should meet the needs of the vast majority of users. If it doesn’t support a feature you need, you can easily subclass it or write your own implementation of JsonMapper instead.

Error Handling

All FacebookClient methods may throw FacebookException, which is an unchecked exception as of RestFB 1.6.

These are the FacebookException subclasses that you may catch:

  • FacebookJsonMappingException

    Thrown when an error occurs when attempting to map Facebook API response JSON to a Java object. It usually indicates that you’ve used the @Facebook annotation on a field with an unsupported type or the Facebook API JSON doesn’t map correctly to the fields you’ve annotated (e.g. attempting to map a JSON string to a Java BigDecimal or a JSON object to a Java List).

    You generally should not explicitly catch this exception in your code, as it usually signifies programmer error in setting up @Facebook annotations. One valid use for catching this exception, however, is to detect when Facebook changes what an API call returns on their end, which would break your live code. It may be useful to catch this exception and then send a notification to you or your ops team to notify them that your application needs to be updated.

  • FacebookNetworkException

    Thrown when a failure occurs at the network level. This can happen if your machine doesn't have a network connection or the Facebook API endpoint returns an unexpected HTTP status code. If there's an HTTP status code available, it's included in the exception so you may take custom actions depending on what type of error occurred.

  • FacebookGraphException

    Thrown when the Graph API returns an error, as shown in the example JSON snippet below. Exposes the type and message so you can handle them in your code and take custom action as needed.

    {
      "error": {
        "type": "SomeBizarreTypeOfException",
        "message": "Everything went wrong."
      }
    }

    Note that FacebookGraphException is a catchall Graph API exception. For your convenience, RestFB will throw more-specific subclasses FacebookOAuthException and FacebookQueryParseException if it detects either of these Graph API error types. These are described below.

  • FacebookOAuthException

    Thrown when the Graph API returns an OAuth-related error (type OAuthException or OAuthAccessTokenException), as shown in the example JSON snippet below.

    {
      "error": {
        "type": "OAuthException",
        "message": "Invalid access token signature."
      }
    }
  • FacebookQueryParseException

    Thrown when the Graph API returns an FQL query parsing error (type QueryParseException), as shown in the example JSON snippet below.

    {
      "error": {
        "type": "QueryParseException",
        "message": "Unknown path components: /fizzle"
      }
    }
  • FacebookResponseStatusException

    This is thrown by RestFB when an FQL call fails. FacebookGraphException and its subclasses are not applicable in that case because Facebook returns this “legacy” exception instead due to FQL not yet being a full-fledged member of the Graph API.

    FacebookResponseStatusException will include both the error code and error message returned by the Facebook API so you may take custom actions depending on the type of error that occurred.

  • FacebookResponseContentException

    This is thrown by RestFB when Facebook responds with unexpected data. For example, when extending an access token, Facebook should return an HTTP response body of the form access_token=123&expires=456. But if Facebook does not respond as expected - perhaps they modify the response format in some future API release - FacebookResponseContentException will be thrown.

    It is unlikely that you will ever see this exception.

Here’s some example code to illustrate the above. Keep in mind that your code doesn’t need to handle every single exception the way we’re doing here - this is just to demonstrate what’s possible.

try {
  Connection<User> myFriends = facebookClient.fetchConnection("me/friends", User.class);

} catch (FacebookJsonMappingException e) {
  // Looks like this API method didn't really return a list of users
} catch (FacebookNetworkException e) {
  // An error occurred at the network level
  out.println("API returned HTTP status code " + e.getHttpStatusCode());
} catch (FacebookOAuthException e) {
  // Authentication failed - bad access token?
} catch (FacebookGraphException e) {
  // The Graph API returned a specific error
  out.println("Call failed. API says: " + e.getErrorMessage());
} catch (FacebookResponseStatusException e) {
  // Old-style Facebook error response.
  // The Graph API only throws these when FQL calls fail.
  // You'll see this exception more if you use the Old REST API
  // via LegacyFacebookClient.
  if (e.getErrorCode() == 200)
    out.println("Permission denied!");
} catch (FacebookException e) {
  // This is the catchall handler for any kind of Facebook exception
}

Here’s some example code to illustrate the above. Keep in mind that your code doesn’t need to handle every single exception the way we’re doing here - this is just to demonstrate what’s possible.

See Facebook documentation

To prevent abuse of the Graph API, Facebook uses a rate limiting mechanism. The number of calls you are allowed to make depends on the kind of request. There are 3 types of limits: app limit, user limit and page limit.

The app limit is connected to the app. As soon as you run into this limit you are in mayor trouble, because no more calls are allowed using this Facebook app. This is a limit that affects all your users and all pages.

The user limit comes into play if you use a user access token. This limit can be reached as soon as a user fires too many requests to Facebook. If you run into this limit, the app can be used by other users and the app limit is not triggered. The user has to wait before new requests can be sent.

The page limit is a bit different and more complicated. This limit is reached if a page access token is used to send too many requests to Facebook. But the page limit is directly connected to the page and not to the application. If any application that manages a page triggers the limit, all applications that use a page access token for this page are in trouble. That’s the reason why Facebook allows the app owner to increase the limit for the page.

RestFB supports the limits and you can fetch the limit information from the WebRequestor. The WebRequestor provides a DebugHeaderInfo with rate limiting and some additional Debug information Facebook provides per call and developers can handle this information and act in accordance with the given limits. In general, the rate limits are not provided until you reach an 80% threshold. As soon as you are above this limit the request contains the rate limit and you can reduce your calls.

The DebugHeaderInfo can be fetched after every client call like this:

DebugHeaderInfo headerInfos = client.getWebRequestor().getDebugHeaderInfo();
System.out.println("App usage: " + headerInfos.getAppUsage());
System.out.println("Page usage: " + headerInfos.getPageUsage());

Extensibility and Unit Testing

In addition to FacebookClient, RestFB provides default implementations for WebRequestor and JsonMapper, two components that DefaultFacebookClient depends on to do its work.

These dependencies are designed to allow for straightforward subclassing (if you only want to replace a little bit of functionality) and simple custom implementations (if you require full control).

This comes in handy when unit testing - for example, you can write your own WebRequestor implementation that simulates a Facebook API endpoint response. You can drop in custom data designed to exercise your application’s Facebook integration or simulate error conditions to make sure you’re handling them properly.

Here’s a trivial example which shows one way you might implement this:

FacebookClient facebookClient = new DefaultFacebookClient(MY_ACCESS_TOKEN,

  // A one-off DefaultWebRequestor for testing that returns a hardcoded JSON
  // object instead of hitting the Facebook API endpoint URL

  new DefaultWebRequestor() {
    @Override
    public Response executeGet(String url) throws IOException {
      return new Response(HttpURLConnection.HTTP_OK,
        "{'id':'123456','name':'Test Person'}");
    }
  }, new DefaultJsonMapper());

// Make an API request using the mocked WebRequestor

User user = facebookClient.fetchObject("ignored", User.class);

// Make sure we got what we were expecting

assert "123456".equals(user.getId());
assert "Test Person".equals(user.getName());

Boost Performance

Generating a SimpleDateFormat instance is incredibly expensive and you should not generate a new formatter for every date string you have to parse. Therefore RestFB provides the possibility to replace the old and slow parsing with a faster solution. But you have to take care of some cleanup because the higher speed can result in a small memory leak. Of course RestFB provides everything you need to do it right.

With version 1.7.0 you can decide which DateFormatStrategy you use. The default strategy is the SimpleDateFormatStrategy. It’s almost the same behavior as in the versions before 1.7.0 and you don’t need to change anything.

The faster stretegy is called CachedDateFormatStrategy. You have to set this manually in the DateUtils singleton and call the clearThreadLocal method at the end of a thread to prevent the memory leak mentioned above. You should have a look at the code example below.

Because we provide the DateFormatStrategy as an interface you can implement your own strategy.

DateUtils.setDateFormatStrategy(new CachedDateFormatStrategy());
// do your normal stuff in that thread
...
// clean the thread local cache just before you finish the thread
DateFormatStrategy strategy = DateUtils.getDateFormatStrategy();
if (strategy instanceof CachedDateFormatStrategy)
  ((CachedDateFormatStrategy)strategy).clearThreadLocal();

See Graph API documentation

You can improve your connection’s performance by using the ETagWebRequestor. This WebRequestor is a special implementation wich adds ETag support to the restfb’s requests. For further information about ETag you should have a look at the wikipedia page.

With the EtagWebRequestor the response body of every single request is stored in a cache. If you send the same request again to the Graph API, a hash key is added to the request header. Facebook will check the hash key and if the new response is the same as the stored one, Facebook returns an HTTP 304 and RestFB uses the cached response body. If an HTTP 200 is received instead, the old cached response body is replaced with the newly received response.

With this Requestor you can cut down on a lot of network traffic and it is very easy to use. This snippet shows how the EtagWebRequestor is created and used in RestFB.

Disable Caching while using EtagWebRequestor

Sometimes it is useful to switch to the non-caching version. The EtagWebRequestor provides the isUseCache and setUseCache methods. With these methods you can ask the Requestor if caching is enabled and switch it to your needs.

// create the special WebRequestor with ETag support
ETagWebRequestor webRequestor = new ETagWebRequestor();
FacebookClient client = 
  new DefaultFacebookClient(accessToken, webRequestor, new DefaultJsonMapper(), Version.VERSION_2_6);

Possible problems

  1. Because every call is stored in the cache, this may lead to a performance degredation if the cache size increases significantly.
  2. The cache uses a SoftHashMap to store the response bodies. If you drive your system to the memory limit, the JVM will remove elements from the cache to allow the system to work normally. If this happens at a really bad time, RestFB may run into problems and you will have to re-try your request.

Links

Visit RestFB’s home on Github.

Have a question not covered here? Ask in the RestFB Google Group.

Found a bug or have an enhancement request? Create a ticket in the issue tracker.

Download a read-only copy of the current source code using Git:

git clone git://github.com/restfb/restfb.git