A Facebook Graph API SDK In Golang
This is a Go package fully supports Facebook Graph API with file upload, batch request, FQL and multi-FQL. It can be used in Google App Engine.
API documents can be found on godoc.
Feel free to create an issue or send me a pull request if you have any "how-to" question or bug or suggestion when using this package. I'll try my best to reply it.
Get It
Use go get -u github.com/huandu/facebook
to get or update it.
Usage
Quick start
Here is a sample to read my Facebook first name by uid.
package main
import (
"fmt"
fb "github.com/huandu/facebook"
)
func main() {
res, _ := fb.Get("/538744468", fb.Params{
"fields": "first_name",
"access_token": "a-valid-access-token",
})
fmt.Println("here is my facebook first name:", res["first_name"])
}
Type of res
is fb.Result
(a.k.a. map[string]interface{}
).
This type has several useful methods to decode res
to any Go type safely.
var first_name string
res.DecodeField("first_name", &first_name)
fmt.Println("alternative way to get first_name:", first_name)
type User struct {
FirstName string
}
var user User
res.Decode(&user)
fmt.Println("print first_name in struct:", user.FirstName)
If a type implements json.Unmarshaler
interface, Decode
or DecodeField
will use it to unmarshal JSON.
res := Result{
"create_time": "2006-01-02 15:16:17Z",
}
var tm time.Time
res.DecodeField("create_time", &tm)
Read a graph user
object with a valid access token
res, err := fb.Get("/me/feed", fb.Params{
"access_token": "a-valid-access-token",
})
if err != nil {
if e, ok := err.(*Error); ok {
fmt.Logf("facebook error. [message:%v] [type:%v] [code:%v] [subcode:%v]",
e.Message, e.Type, e.Code, e.ErrorSubcode)
return
}
return
}
fmt.Println("my latest feed story is:", res.Get("data.0.story"))
Read a graph search
for page and decode slice of maps
res, _ := fb.Get("/search", fb.Params{
"access_token": "a-valid-access-token",
"type": "page",
"q": "nightlife,singapore",
})
var items []fb.Result
err := res.DecodeField("data", &items)
if err != nil {
fmt.Logf("An error has happened %v", err)
return
}
for _, item := range items {
fmt.Println(item["id"])
}
Use App
and Session
It's recommended to use App
and Session
in a production app. They provide more controls over all API calls. They can also make code clear and concise.
var globalApp = fb.New("your-app-id", "your-app-secret")
globalApp.RedirectUri = "http://your.site/canvas/url/"
session, _ := globalApp.SessionFromSignedRequest(signedRequest)
session := globalApp.Session(token)
err := session.Validate()
res, _ := session.Get("/me/feed", nil)
Use paging
field in response.
Some Graph API responses use a special JSON structure to provide paging information. Use Result.Paging()
to walk through all data in such results.
res, _ := session.Get("/me/home", nil)
paging, _ := res.Paging(session)
results := paging.Data()
noMore, err := paging.Next()
results = paging.Data()
Read graph api response and decode result into a struct
As facebook Graph API always uses lower case words as keys in API response.
This package can convert go's camel-case-style struct field name to facebook's underscore-style API key name.
For instance, to decode following JSON response...
{
"foo_bar": "player"
}
One can use following struct.
type Data struct {
FooBar string
}
Decoding behavior can be changed per field through field tag -- just like what encoding/json
does.
Following is a sample shows all possible field tags.
type FacebookFeed struct {
Id string `facebook:",required"`
Story string
FeedFrom *FacebookFeedFrom `facebook:"from"`
CreatedTime string `facebook:"created_time,required"`
Omitted string `facebook:"-"`
}
type FacebookFeedFrom struct {
Name, Id string
}
var feed FacebookFeed
res, _ := session.Get("/me/feed", nil)
res.DecodeField("data.0", &feed)
Send a batch request
params1 := Params{
"method": fb.GET,
"relative_url": "me",
}
params2 := Params{
"method": fb.GET,
"relative_url": uint64(100002828925788),
}
results, err := fb.BatchApi(your_access_token, params1, params2)
if err != nil {
return
}
batchResult1, _ := results[0].Batch()
batchResult2, _ := results[1].Batch()
var id string
res := batchResult1.Result
res.DecodeField("id", &id)
contentType := batchResult1.Header.Get("Content-Type")
Send FQL query
results, _ := fb.FQL("SELECT username FROM page WHERE page_id = 20531316728")
fmt.Println(results[0]["username"])
session := &fb.Session{}
session.SetAccessToken("A-VALID-ACCESS-TOKEN")
results, _ := session.FQL("SELECT username FROM page WHERE page_id = 20531316728")
fmt.Println(results[0]["username"])
Make multi-FQL
res, _ := fb.MultiFQL(Params{
"query1": "SELECT username FROM page WHERE page_id = 20531316728",
"query2": "SELECT uid FROM user WHERE uid = 538744468",
})
var query1, query2 []Result
res.DecodeField("query1", &query1)
res.DecodeField("query2", &query2)
session := &fb.Session{}
session.SetAccessToken("A-VALID-ACCESS-TOKEN")
res, _ := session.MultiFQL(Params{
"query1": "...",
"query2": "...",
})
Use it in Google App Engine
Google App Engine provide appengine/urlfetch
package as standard http client package. Default client in net/http
doesn't work. One must explicitly set http client in Session
to make it work.
import (
"appengine"
"appengine/urlfetch"
)
var context appengine.Context
seesion := globalApp.Session("a-access-token")
session.HttpClient = urlfetch.Client(context)
res, err := session.Get("/me", nil)
Select Graph API version
See Platform Versioning to understand facebook versioning strategy.
fb.Version = "v2.0"
fb.Api("huan.du", GET, nil)
session := &fb.Session{}
session.Version = "v2.0"
Enable appsecret_proof
Facebook can verify Graph API Calls with appsecret_proof
. It's a feature to make Graph API call more secure. See Securing Graph API Requests to know more about it.
globalApp := fb.New("your-app-id", "your-app-secret")
globalApp.EnableAppsecretProof = true
session := globalApp.Session("a-valid-access-token")
session.Get("/me", nil)
session.EnableAppsecretProof(false)
Debugging API Requests
Facebook introduces a way to debug graph API calls. See Debugging API Requests for details.
This package provides both package level and per session debug flag. Set Debug
to a DEBUG_*
constant to change debug mode globally; or use Session#SetDebug
to change debug mode for one session.
When debug mode is turned on, use Result#DebugInfo
to get DebugInfo
struct from result.
fb.Debug = fb.DEBUG_ALL
res, _ := fb.Get("/me", fb.Params{"access_token": "xxx"})
debugInfo := res.DebugInfo()
fmt.Println("http headers:", debugInfo.Header)
fmt.Println("facebook api version:", debugInfo.FacebookApiVersion)
Work with package golang.org/x/oauth2
Package golang.org/x/oauth2
can handle facebook OAuth2 authentication process and access token very well. This package can work with it by setting Session#HttpClient
to OAuth2's client.
import (
"golang.org/x/oauth2"
oauth2fb "golang.org/x/oauth2/facebook"
fb "github.com/huandu/facebook"
)
conf := &oauth2.Config{
ClientID: "AppId",
ClientSecret: "AppSecret",
RedirectURL: "CallbackURL",
Scopes: []string{"email"},
Endpoint: oauth2fb.Endpoint,
}
token, err := conf.Exchange(oauth2.NoContext, "code")
client := conf.Client(oauth2.NoContext, token)
session := &fb.Session{
Version: "v2.4",
HttpClient: client,
}
res, _ := session.Get("/me", nil)
Change Log
See CHANGELOG.md.
Out of Scope
- No OAuth integration. This package only provides APIs to parse/verify access token and code generated in OAuth 2.0 authentication process.
- No old RESTful API support. Such APIs are deprecated for years. Forget about them.
License
This package is licensed under MIT license. See LICENSE for details.