Facebook Graph API & Demo Example

Social Demo - FaceBook
常用Graph API說明與Example Demo。
Facebook Graph API & Social Demo Example

什麼是Graph API?

Graph API是Facebook所推出的一種技術標準,它的核心概念是「物件與連結」。
為什麼稱為「Graph API」呢?
因為整個Facebook就是透過這些物件與連結建立而成的Social Graph。
Facebook所提供存取的介面,就稱為「Graph API」。
(參考Graph API是什麼東東?)
例如,我可以經由我的ID(物件 "ME" ) -> Graph API(連結) -> 取得朋友、喜愛的電影、Po文(物件)。
Facebook Graph API

如何使用Graph API?

有多種方式使用Graph API,我們可以使用http request與Javascript SDK等方式。
使用http request:
公式為: https://graph.facebook.com/ID/TARGET_OBJECT?oauth_token=[oauth_token]
https://graph.facebook.com/ID/TARGET_OBJECT?access_token=[access_toke]
ID為物件的ID,TARGET_OBJECT 為想要取得的物件。另外,若需取得使用者同意才能獲得的資料,需要加上oauth_token。 
例如,想要取得自己的喜愛的電影,則可這樣用:
https://graph.facebook.com/me/movies?oauth_token=CAAAA...
使用Javascript SDK:
FB.api('/me/movies', function(response) { console.log(response); });

OAuth 2 / Access Token

第三方網站(App)如果想要跟Facebook取得特定使用者的資料,必須使用Access Toke來得到。
例如:
//公式:https://graph.facebook.com/me?access_token=[access_toke]

https://graph.facebook.com/me?access_token=CAAAA......
得到資料:
{
   "id": "10200976708138630",
   "first_name": "Hsin-Hao",
   "gender": "female",
   "last_name": "Tang",
   "link": "https://www.facebook.com/cythilya",
   "locale": "en_US",
   "name": "Hsin-Hao Tang",
   "timezone": 8,
   "updated_time": "2014-05-23T10:04:39+0000",
   "username": "cythilya",
   "verified": true
}

Demo

此Demo範例共有以下的頁面:首頁、關於我、Feed、Friends、Post、Invite、Check、Comment、Permission Revoke。
範例網站:Social Demo - Facebook

首頁

來到首頁,就會有登入與授權的狀況。來補談OAuth 2 Token Flow吧。

OAuth 2 Token Flow

OAuth 2 Token Flow
使用者在使用App前,App會先將使用者送到Facebook做請求授權的動作,Facebook授權此App可暫時存取特定資料,App會取得一組特定的Access Token字串。App就可以利用這Access Token做登入、存取資料的動作。

取得Access Token

FB.getLoginStatus(function(response) {
    if (response.status === 'connected') {
        // the user is logged in and has authenticated your app,
        // and response.authResponse supplies
        // the user's ID, a valid access token, a signed request, 
        // and the time the access token and signed request each expire

        //get access token, and save it in local storage
        localStorage.setItem('accessToken', response.authResponse.accessToken);

        //check user, in order to get user info
        checkUser();
    }
    else if (response.status === 'not_authorized') {
        // the user is logged in to Facebook, but has not authenticated the app
    }
    else {
        //response.status === 'unknown'
        // the user isn't logged in to Facebook.
    }
});
若使用者狀態若為"connected",則表示使用者已授權並登入此App,因此會回傳一個物件。
回傳的物件為:Object {authResponse: Object, status: "connected"}
此物件包含User ID、Access Token、Access Token可使用的時間、使用者狀態。
若使用者狀態若為"not_authorized",則表示使用者並未授權App,此時會導到Facebook授權的畫面。
回傳的物件為:Object {authResponse: undefined, status: "not_authorized"}

登入與導回首頁

按下Login Button後,經由redirect字串做登入的動作。
https://www.facebook.com/dialog/oauth?client_id=[APP_ID]&redirect_uri=[REDIRECT_URL]
APP_ID為App的ID,REDIRECT_URL為轉跳回來的URL。
導到Facebook登入頁面,完成登入後轉跳回指定畫面(即首頁)。
程式碼如下。
var dLogin = $('.login');

dLogin.click(function(e){

    //click login button
    //redirect to fb login page
    //after logging in, back to index
    var redirect = 'https://www.facebook.com/dialog/oauth?client_id=132069051838&redirect_uri=http://localhost/social_demo/fb_greeting';

    location.href = redirect;
});

畫面展示

若尚未登入Facebook,按下右上角Login Button後,會導到Facebook登入畫面。
Facebook Login
Facebook登入畫面。
Facebook Login
登入成功。
Facebook Login

若未授權,按下右上角Login Button後,會出現請求授權的Popup。授權完畢後,再導回首頁。
Facebook APP 授權

關於我

取得自己的公開資訊。
使用http request:
https://graph.facebook.com/me?access_token=CAAAAH...
使用Javascript SDK:
FB.api('/me', function(response) {
    console.log(response);

    //id
    if(id != undefined) {
        var picture = 'http://graph.facebook.com/'+ response.id +'/picture?width=140&height=140';
        dUserProfileBlock.find('.id').html(id);
        dUserProfileBlock.find('.img-thumbnail').attr('src', picture);
    }
    else {
        //no op
    }
});
取得資訊:
{
   "id": "10200976708138630",
   "first_name": "Hsin-Hao",
   "gender": "female",
   "last_name": "Tang",
   "link": "https://www.facebook.com/cythilya",
   "locale": "en_US",
   "name": "Hsin-Hao Tang",
   "timezone": 8,
   "updated_time": "2014-05-23T10:04:39+0000",
   "username": "cythilya",
   "verified": true
}

Feed

取得自己的分享內容。
Facebook Feed
使用Graph API:FB.api("/me/feed")
FB.api('/me/feed', function(response) {
    console.log(response);

    if (response && !response.error) {
        var feedData = response.data;
        console.log(response.data);
    }
});     
回傳一個物件response,response.data包含Feed的資料(含標題、連結、預覽圖等),response.paging為一個網址,可找到上(多)筆或下(多)筆的資料。
Facebook Feed

Friends

取得好友名單。
Facebook , friends, 取得好友名單
使用Graph API:FB.api("/me/taggable_friends")
FB.api('/me/taggable_friends', function(response) {
    //taggable_friends: A list of friends that can be tagged or mentioned in stories published to Facebook.

    if (response && !response.error) {
        console.log(response);
    }
}); 
taggable_friends是可被Tag或在FB貼文中標註的朋友。 之前的"friends"已經無法使用。
回傳一個物件response(Object {data: Array[785], paging: Object}),response.data包含朋友的資料,含id、name、picture。但id並非真實的User ID,而是不同的App對於不同的使用者,分別取得不同的ID。因此無法跟之前一樣,直接利用這個假ID去取使用者的公開資料。

Post by Graph API / UI

貼文有兩種方式,可使用Graph API或Facebook提供的UI來PO文。

Post by Graph API

使用Graph API:FB.api("/me/feed", "post", data)
Demo頁面的資料填寫欄位。 Post by Graph API
    var params = {};
    params['name'] = "Social Demo";
    params['caption'] = "BBC One - Sherlock, Series 1"; 
    params['message'] = 'Worth a share.';;
    params['description'] = "Sherlock Holmes and Dr John Watson's adventures in 21st Century London. A thrilling, funny, fast-paced contemporary reimagining of the Arthur Conan Doyle classic. Made by Hartswood Films.";
    params['link'] = "http://www.bbc.co.uk/programmes/b00t4pgh";
    params['picture'] = "http://goo.gl/RNpxEN";

    FB.api('/me/feed', 'post', params, function(response) {
        if (!response || response.error) {
            alert('Error occured');
        } 
        else {
            //回傳貼文的ID,之後可經由此ID刪除貼文  
            alert('Post ID: ' + response.id);
        }
    });
PO文成功會回傳Post ID。
Post by Graph API

記得要取得公開貼文的權限

FB.login(function(response) {
    //login...
}, {scope: 'publish_actions'}); 
scope的權限以逗號分隔,若要額外取得使用者的公開發表和Email的權限,則在login的function後加上 {scope:"publish_actions,email"}。當使用者登入時,就會看到Facebook要求這些額外的權限。

Facebook介面呈現與欄位對照

Facebook Post by Graph API

Post by UI

使用Facebook提供的UI來PO文,可在此調整PO文的對象。
var dPostUI = $('.postui'); //click Post UI button

dPostUI.click(function(e){
    e.preventDefault();

    FB.ui({
        method: 'feed',
        name: 'Social Demo',
        caption: 'BBC One - Sherlock, Series 1',
        description: 'Sherlock Holmes and Dr John Watson\'s adventures in 21st Century London. A thrilling, funny, fast-paced contemporary reimagining of the Arthur Conan Doyle classic. Made by Hartswood Films.',
        link: 'http://www.bbc.co.uk/programmes/b00t4pgh',
        picture: 'http://goo.gl/9ngEIK'
    }, 
    function(response) {
        console.log('publishStory response: ', response);
    });                 
}); 

Facebook介面呈現與欄位對照

Facebook Post by UI
備註:目前經由UI分享的權重高於使用Graph API分享。權重牽涉到使用者是否可在自己的動態牆上看到該則訊息。私心的認為這是為了之後的廣告收費鋪路...

Invite

經由APP邀請好友。

經由APP邀請好友的UI程式碼

var dBtnInviteFriends = $('.inviteFriends');

dBtnInviteFriends.click(function(){
    FB.ui({
        method: 'apprequests',
        message: 'Greeting'
    });
});
按下按鈕"Invite Friends"跳出Popup,可選擇好友後送出邀請。
回傳的res為一個物件。
Object {request: "1430775300521224", to: Array[1], e2e: "{"submit_0":1402112773854}"}
物件中包含(邀請使用的)使用者ID。
而我們可以經由這個ID與Access Token查到發送的來源與目的地、訊息與時間。
例如我們可以這樣查詢:
https://graph.facebook.com/1430775300521224?access_token=CAAAAH...
即可得到:
{
   "id": "1430775300521224",
   "application": {
      "name": "Greeting",
      "namespace": "cythilya",
      "id": "132069051838"
   },
   "from": {
      "id": "10200976708138630",
      "name": "Hsin-Hao Tang"
   },
   "message": "Greeting",
   "created_time": "2014-06-07T03:46:14+0000"
}

經由APP邀請好友的UI畫面

Facebook 經由APP邀請好友

取得使用此App的朋友

var fql = 'SELECT uid, name, pic_square, is_app_user FROM user ' + 
          'WHERE uid IN (SELECT uid2 FROM friend WHERE uid1 = me()) ' + 
          'OR uid IN(SELECT uid1 FROM friend WHERE uid2=me()) ORDER BY name';


FB.api('/fql', 'get',{ q: fql}, function(response) {
    if(response.data) {
        console.log(response.data);
    } 
    else {
        alert('Try again later.')
    }
}); 
response.data即為安裝此App的好友,即Demo頁面的三位好友。
Facebook 經由APP邀請好友

確認是否對特定粉絲頁按讚

使用Graph API:FB.api("me?fields=likes")
先取得按讚過的粉絲頁,並對這些粉絲頁的ID做比對。
//get my like list
FB.api('me?fields=likes', function(response) {
    if (response && !response.error && response.likes != null ) {
        var likeData = response.likes.data;
        var nextUrl = getParameterByName('after', response.likes.paging.next);
        var stop = false;                               

        $.each(likeData, function(index, value){
            //對這一頁的列表做比對
            if(id == value.id){
                dCheckLikeFanGroupMessage.html('Match');
                stop = true;
            }
        });

        if(!stop && nextUrl != null) {
            //假設這一頁沒有查到,且有下一頁的列表存在,則接著比對下一頁
            checkID(id, nextUrl);
        }                               
    }
    else {
        //Try again later
    }
}); 
取得URL中特定參數的function。
//get parameter
var getParameterByName = function(name, href) {
    name = name.replace(/[\[]/,"\\\[").replace(/[\]]/,"\\\]");
    var regexS = "[\\?&]"+name+"=([^&#]*)";
    var regex = new RegExp( regexS );
    var results = regex.exec( href );

    if( results == null ){
        return "";
    }
    else{
        return decodeURIComponent(results[1].replace(/\+/g, " "));
    }
}
若在列表中比對到,表示有按讚過,則會出現Match,否則出現None Match
由於列表並非一次傳回所有按讚過的粉絲團,要一頁一頁取。
因此若現在這一頁的列表沒有,就要取下一頁做比對。
var checkID = function(id, nextUrl){
    var targetId = id;
    var nextPageUrl = nextUrl;

    FB.api(myID + '/likes?limit=25&after=' + nextUrl, function(response) {
        var nextData = response.data;
        var nextUrl = getParameterByName('after', response.paging.next);
        var stop = false;

        $.each(nextData, function(index, value){
            if(targetId == value.id) {
                stop = true;
                console.log('Match');
            }
        });

        //resursive
        if(!stop && nextUrl != "") {
            checkID(targetId, nextUrl);
        }   

        if(stop == false && nextUrl == ""){
            console.log('None Match');
        }
    }); 
};  

留言

在view上放置html code並用js做FB.init()即可使用。
<div class="fb-comments" data-href="http://www.bbc.co.uk/programmes/b018ttws" data-numposts="5" data-colorscheme="light"></div>

刪除授權

使用Graph API:FB.api("/me/permissions", "delete")
按下"Revoke Permission"按鈕,以刪除權限。
Facebook Graph API 刪除授權
FB.api('/me/permissions', 'delete', function(res) {
    if (res && !res.error) {
        if(res){
            alert('Permission revoked.');
        }
        else {
            alert('Permissions delete error.');
        }                           
    }
    else {
        alert('Try again later.');
    }
});
刪除成功res會回傳ture。

Demo範例網站

Source Code 下載程式碼
以上如果有任何補充或錯誤的地方也請告知,謝謝。

參考資料


因為部落格搬家了,因此在新落格也放了一份,未來若有增刪會在這裡更新-Facebook Graph API & Demo Example

留言