Newest Version of the library is available via RestFB's home on Github.
View the changelog, or download it here.

The project zip contains sample code in the source/example directory which can help you get up and running quickly.

RestFB is a single JAR - just drop it into your app and you're ready to go. Download it from Maven Central:

maven central restfb version


Design goals:

  • Minimal public API
  • Maximal extensibility
  • Robustness in the face of frequent Facebook API changes
  • Simple metadata-driven configuration
  • Zero runtime dependencies


  • Support for non-Graph/non-REST API parts of the Facebook Platform
  • Providing a mechanism for obtaining session keys or OAuth access tokens
  • Using XML as a data transfer format in addition to JSON
  • Formally-typed versions of all Facebook API methods, error codes, etc.

If RestFB doesn't meet your needs, check out sister project BatchFB. It's a good lower-level client, especially if you're concerned with batching and performance.

How To Use It

You can run some sample code, jump straight to the RestFB Javadoc, or learn by example below.

If you're looking for help or additional examples, please check out the RestFB Google Group or visit the source/examples directory in the RestFB distribution.

Working with source code

It's easy to work directly with the RestFB source code. This is necessary if you need to use an unreleased version or want to contribute to the code. It's very important to know that RestFB is using the lombok code generator. All types use special annotations to generate the boilerplate code for the setters and getters. It's important to know that we made the design decision to handle Lists and Maps differently - the lombok annotations are not used for them and we provide add(), remove() and getList() methods. The returned List is immutable to prevent inner Lists and Maps from being altered in other object. This idea can be found at Martin Fowler's blog.

You have to install lombok in your IDE to compile RestFB. If you don't do this, you will see a lot of compile errors and missing methods. Further information regarding the installation of lombok into the different IDEs can be found here.

Contributing to RestFB

Contributing code is a essential part of open source and we try to make this as easy as possible. You need only to fork RestFB at Github and send us a pull request. We have some prerequisites to merge the pull request in our Dev branch.

  • The code must be formatted with our code formatter (have a look at the misc folder)
  • The code must meet our design decisions
  • Existing unit tests have to run without error (we use a CI)
  • The pull request should be mergeable
  • Explain why you made the change and what's the benefit
  • jUnit tests are a big plus
  • The pull request should be based on the dev branch
  • Group and squash your commits, less are better

This conditions are defined to make everyone's lives easier and cause fewer conflicts when merging a pull request into the dev branch. If you put some work in a pull request and it meets our requirements, it's very likely we'll merge it the same day.

If you don't want to dive into the RestFB code you may open an issue. We are very thankful for every issue you open, no matter what kind it is. We solve bugs, explain Facebook and answer your RestFB or Facebook questions.


// DefaultFacebookClient is the FacebookClient implementation
// that ships with RestFB. You can customize it by passing in
// custom JsonMapper and WebRequestor implementations, or simply
// write your own FacebookClient instead for maximum control.

FacebookClient facebookClient = new DefaultFacebookClient(MY_ACCESS_TOKEN);

// It's also possible to create a client that can only access
// publicly-visible data - no access token required.
// Note that many of the examples below will not work unless you supply an access token!

FacebookClient publicOnlyFacebookClient = new DefaultFacebookClient();

// Get added security by using your app secret:

FacebookClient facebookClient = new DefaultFacebookClient(MY_ACCESS_TOKEN, MY_APP_SECRET);


Fetching Single Objects

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);

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

Fetching Multiple Objects

See Graph API documentation

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

out.println("User name: " +;
out.println("Page likes: " +;


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

public class FetchObjectsResults {
  User me;

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

  Page page;

Fetching Objects

Some requests - like the comments of a post - are returned as a list. Because these lists can be very large, Facebook provides a paging mechanism.

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.

A common use case is to fetch all elements of a specific endpoint and work with these 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<User> myFriends = facebookClient.fetchConnection("me/friends", User.class);
Connection<Post> myFeed = facebookClient.fetchConnection("me/feed", Post.class);

out.println("Count of my friends: " + myFriends.getData().size());
out.println("First item in my feed: " + myFeed.getData().get(0));

// Connections support paging and are iterable

for (List<Post> myFeedConnectionPage : myFeed)
  for (Post post : myFeedConnectionPage)
    out.println("Post: " + post);

In some rare cases you may need to prevent RestFB from automatically loading further results. So you must not use the normal iteration process and use a different approach instead. You can simply work with the very common iterator pattern. Or you can use the Connection.hasNext() and methods on a connection object.

For debugging purposes you can call the Connection.getNextPageUrl() or Connection.getPreviousPageUrl() and do something important with the returned string. It will contain the exact URL containing the access token and additional query parameters to fetch the next or the previous page.

Fetching Insights

// 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())


A few words...

Logging Example

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

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
} finally {
  // Make sure to tear down when you're done using the bridge


# Example entries
# ==================================

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

# the complete restfb package logging can be configured like this


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

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 still provide access to FQL, because some Applications out there are still using Graph API 2.0. On August 7, 2016 Facebook will disable support for both Graph API 2.0 and FQL.

Executing FQL Queries

See FQL documentation

String query = "SELECT uid, name FROM user WHERE uid=220439 or uid=7901103";
List<FqlUser> users = facebookClient.executeFqlQuery(query, FqlUser.class);

out.println("Users: " + users);


// Holds results from an "executeFqlQuery" call.
// You need to write this class yourself!
// Be aware that FQL fields don't always map to Graph API Object fields.

public class FqlUser {
  String uid;

  String name;

  public String toString() {
    return String.format("%s (%s)", name, uid);

Executing Multiple FQL Queries in One Call

See FQL documentation

Map<String, String> queries = new HashMap<String, String>() {
    put("users", "SELECT uid, name FROM user WHERE uid=220439 OR uid=7901103");
    put("likers", "SELECT user_id FROM like WHERE object_id=122788341354")

MultiqueryResults multiqueryResults =
  facebookClient.executeFqlMultiquery(queries, MultiqueryResults.class);

out.println("Users: " + multiqueryResults.users);
out.println("People who liked: " + multiqueryResults.likers);


// Holds results from an "executeFqlMultiquery" call.
// You need to write these classes yourself (along with the FqlUser class above)!

public class FqlLiker {
  String userId;

  public String toString() {
    return userId;

public class MultiqueryResults {
  List<FqlUser> users;

  List<FqlLiker> likers;

Advanced Usage

Metadata & Introspection

See Graph API documentation

// 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());

Passing Parameters

See Graph API documentation

// 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());

Selecting Specific Fields & Field Expansion

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}"));

Fetch Post with comments/likes total count

see July 2013 Breaking Changes

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

out.println("Likes count: " + post.getLikesCount());
out.println("Likes count (from Likes): " + post.getLikes().getCount());
out.println("Comments count: " + post.getComments().getTotalCount());

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.

// Here's how to fetch a single object

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

// Here's how to fetch a connection

JsonObject photosConnection = facebookClient.fetchObject("me/photos", JsonObject.class);
String firstPhotoUrl = photosConnection.getJsonArray("data").getJsonObject(0).getString("source");

// Here's how to handle an FQL query

String query = "SELECT uid, name FROM user WHERE uid=220439 or uid=7901103";
List<JsonObject> queryResults = facebookClient.executeFqlQuery(query, JsonObject.class);

// Sometimes it's helpful to use JsonMapper directly if you're working with JsonObjects.

List<String> ids = new ArrayList<String>();

// 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(""), Url.class);

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


Publishing a Message and Event

See Graph API documentation

// Publishing a simple message.
// FacebookType represents any Facebook Graph Object that has an ID property.

FacebookType publishMessageResponse =
  facebookClient.publish("me/feed", FacebookType.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);

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

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

Publishing a Photo

See Graph API documentation

// 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.

FacebookType publishPhotoResponse = facebookClient.publish("me/photos", FacebookType.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", FacebookType.class,
  BinaryAttachment.with("", getClass().getResourceAsStream("/")),
  Parameter.with("description", "Test cat"));

Publishing a Checkin

See Graph API documentation

Map<String, String> coordinates = new HashMap<String, String>();
coordinates.put("latitude", "37.06");
coordinates.put("longitude", "-95.67");

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

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

Publishing a Video Via Resumable Upload

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];;

     // Make the request to Facebook
     ResumableUploadTransferResponse filePart = fbc.publish("PAGE_ID/videos",
      // The returned object 
	  // 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",
     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.


See Graph API documentation

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

Batch API

Using Batch Request 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")
  .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);

// 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)

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


Including Binary Attachments Using the Batch Request API

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"))

// 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("", getClass().getResourceAsStream("/")),
  BinaryAttachment.with("", getClass().getResourceAsStream("/")));

// Finally, execute the batch.

facebookClient.executeBatch(batchRequests, binaryAttachments);

Access Token Operations

Get Login Dialog URL

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();

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

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

Extending an Access Token

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,

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

Getting an Application Access Token

See Graph API documentation

// 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);

Getting an Device Access Token

See Graph API documentation

With the Device Access Token Facebook provides a possibility to connect to devices with limited input or display capabilities. RestFB supports this kind of access tokens since version 1.12.0.

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 he have to enter it on a special Facebook page. The url is part of the DeviceCode object. As soon as you presented these information to the user, you have to poll Facebook and try to fetch the device access token.

DefaultFacebookClient client = new DefaultFacebookClient(Version.VERSION_2_3);
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);

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

// 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);

Security Operations

Parsing Signed Requests

// 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 {
  String userId;

  String oauthToken;

  Long expires;

  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

Parsing Deauthorization Callback request

// 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());

Generating appsecret_proof

// 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);

// 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(
out.println("Here's my proof: " + proof);

Running The Examples

RestFB comes with a few example Java source files that you can run and tweak yourself. Don't forget to put your access token inside the quotes!

$ cd source/example
$ ant run-reader-examples "-Daccess_token=MY_ACCESS_TOKEN"
$ ant run-publisher-examples "-Daccess_token=MY_ACCESS_TOKEN"
$ ant 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 {
  String name;

  BigDecimal value;

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

  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.

  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.

String query = "SELECT name FROM user WHERE uid=220439 or uid=7901103";

try {
  List<User> users = facebookClient.executeFqlQuery(query, 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.

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() {
    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)

ETag support

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.

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


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://

RestFB Users

You would like to see your logo here, too?

If you're a happy RestFB user and would like to add a link to your site, please send me an email.


RestFB was created by Mark Allen, is maintained by Norbert Bartels, and sponsored by Transmogrify, LLC.

Transmogrify is a Philadelphia-area software shop specializing in product design and web/mobile software development. Our experience runs the gamut from embedded systems to Oracle DBA work to the cutting-edge web framework and iOS/Android technologies. Give us a call at (215) 436-XMOG or send an email to if you need a hand with anything software-related. We can handle every part of the software lifecycle, from initial requirements and design to ongoing maintenance and support.

Development of RestFB was aided by

Website icons provided by Mark James.


RestFB is open source software released under the terms of the MIT License:

Copyright (c) 2010-2015 Mark Allen, Norbert Bartels.

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.