How does Facebook Graph API Pagination works and how to iterate facebook user feed with it?
First up a bit of terminology:
nodes - basically "things" such as a User, a Photo, a Page, a Comment
edges - the connections between "things", such as a Page's Photos, or a Photo's Comments
fields - info about those "things", such as a person's birthday, or the name of a Page
When you make an API request to a node or edge, you usually don't receive all of the results of that request in a single response. This is because some responses could contain thousands of objects so most responses are paginated by default.
To get all posts by a user you have 3 options:
Cursor-based Pagination
Cursor-based pagination is the most efficient method of paging and should always be used where possible. A cursor refers to a random string of characters which marks a specific item in a list of data. Unless this item is deleted, the cursor will always point to the same part of the list, but will be invalidated if an item is removed. Therefore, your app shouldn't store any older cursors or assume that they will still be valid.
When reading an edge that supports cursor pagination, you will see the following JSON response:
{
"data": [
... Endpoint data is here
],
"paging": {
"cursors": {
"after": "MTAxNTExOTQ1MjAwNzI5NDE=",
"before": "NDMyNzQyODI3OTQw"
},
"previous": "https://graph.facebook.com/me/albums?limit=25&before=NDMyNzQyODI3OTQw"
"next": "https://graph.facebook.com/me/albums?limit=25&after=MTAxNTExOTQ1MjAwNzI5NDE="
}
}
To get all posts by a user you keep surfing the "next" edges (upserting new items). This is how I do it when I dump entire groups into RDBMS's for statistical analysis. Often you will see edges with nodes you have already encountered, that's why I mention to UPSERT (update if it exists otherwise insert).
Time-based Pagination
Time pagination is used to navigate through results data using Unix timestamps which point to specific times in a list of data.
When using an endpoint that uses time-based pagination, you will see the following JSON response:
{
"data": [
... Endpoint data is here
],
"paging": {
"previous": "https://graph.facebook.com/me/feed?limit=25&since=1364849754",
"next": "https://graph.facebook.com/me/feed?limit=25&until=1364587774"
}
}
To get all a users posts you keep iterating back in time. This method will get you the posts in order, although may want them returned in an order by FaceBooks edge algorithm.
Offset-based Pagination
Offset pagination can be used when you do not care about chronology and just want a specific number of objects returned. This should only be used if the edge does not support cursor or time-based pagination.
So what you have found with Offset is the closest you will get to the stock-standard pagination you desire. However:
Offset based pagination is not supported for all API calls. To get consistent results, we recommend you to paginate using the previous/next links we return in the response.
You can read all this in the FB API docs.
https://developers.facebook.com/docs/graph-api/overview/
https://developers.facebook.com/docs/graph-api/using-graph-api/
Finally after doing some researches and reading some blogs I found out that there is no direct API CAlls
from facebook to fetch all user feeder posts in once.
To achieve that functionality either one has to go for infinite scrolling as suggested by Jeremy Thomson or to iterate through different facebook data pages regardless of which facebook pagination
type is supported by the edge
. As far as I want a process without user interference/actions I would definitely go the second option which is iterating through facebook data pages with a while
loop.
To do That we first need our two most important parameters (facebook access_token
+ (facebook appsecret_proof
) as described below:
var appsecret_proof = access_token.GenerateAppSecretProof();
var fb = new FacebookClient(access_token);
Point to be remembered: facebook
access_token
is generated byHttpContext
class.
The facebook API
call will get the users first 25 feeder post as below:
dynamic myFeed = await fb.GetTaskAsync(
("me/feed?fields=id,from {{id, name, picture{{url}} }},story,picture,link,name,description," +
"message,type,created_time,likes,comments")
.GraphAPICall(appsecret_proof));
The API
Call above return results in a Json
array and that should be hydrated through the Model View
properties as shown here:
var postList = new List<FacebookPostViewModel>();
foreach (dynamic post in myFeed.data)
{
postList.Add(DynamicExtension.ToStatic<FacebookPostViewModel>(post));
}
Until here everything was clear before, the most important part which is surely fetching all facebook user post is now in action. For that we need to set a string
NextPageUri
to empty as here:
string NextPageURI = string.Empty;
The final part of all is to check if there is another page for the data, If yes should iterate and add the data to the View Model
until there is no page lift as shown here:
while (myFeed.paging != null && myFeed.paging.next != null)
{
NextPageURI = myFeed.paging.next;
var nextURL = GetNextPageQuery(NextPageURI, access_token);
dynamic nextPagedResult = await fb.GetTaskAsync(nextURL.GraphAPICall(appsecret_proof));
foreach (dynamic post in nextPagedResult.data)
{
postList.Add(DynamicExtension.ToStatic<FacebookPostViewModel>(post));
}
}
This helped me to get rid of the problem faced. But yet I have another task in hand to work on. It is the speed of fetching the posts that if posts are morethan 30k would take 10 minutes which is not ideal at least for me.