UNPKG

12.2 kBMarkdownView Raw
1# Stay Classy, Facebook
2
3[FBgraph](http://criso.github.com/fbgraph/) is a nodejs module that provides easy access to the facebook graph api
4
5### Version: 0.2.11
6
7## Oh nooooooesss - MOAR facebook
8
9 I created this because I wanted to access FB's graph from `node`.
10 The libraries I found, felt clunky to me, and I needed an excuse to create a node module.
11
12 All calls will return `json`. Facebook sometimes (on friend requests, deleting test users, access token request)
13 decides to just return a `string` or `true` or redirects directly to the image. I say __nay-nay__! Let's make it Disney, and keep things consistent!
14
15
16## Installation via npm
17 $ npm install fbgraph
18
19 var graph = require('fbgraph');
20
21## Authentication
22
23If you get an accesstoken via some other Oauth module like [everyauth](https://github.com/bnoguchi/everyauth) ,
24[connect-auth](https://github.com/ciaranj/connect-auth) or [node-oauth](https://github.com/ciaranj/node-oauth) you can just set
25the access token directly. Most `get` calls, and pretty much all `post` calls will require an `access_token`
26
27
28### Static access token (used on all calls)
29```js
30 graph.setAccessToken(access_token);
31```
32
33### To use a specific access token for a particular request
34```js
35 // pass it in as part of the url
36 graph.post(userId + "/feed?access_token=007", wallPost, function(err, res) {
37 // returns the post id
38 console.log(res); // { id: xxxxx}
39 });
40
41```
42
43
44This is how you would get authenticated using only the `fbgraph` module.
45More details below on the __express app__ section
46
47```js
48 // get authorization url
49 var authUrl = graph.getOauthUrl({
50 "client_id": conf.client_id
51 , "redirect_uri": conf.redirect_uri
52 });
53
54 // shows dialog
55 res.redirect(authUrl);
56
57 // after user click, auth `code` will be set
58 // we'll send that and get the access token
59 graph.authorize({
60 "client_id": conf.client_id
61 , "redirect_uri": conf.redirect_uri
62 , "client_secret": conf.client_secret
63 , "code": req.query.code
64 }, function (err, facebookRes) {
65 res.redirect('/loggedIn');
66 });
67```
68
69### Securing API calls
70
71Facebook [recommends](https://developers.facebook.com/docs/reference/api/securing-graph-api/) adding the
72`appsecret_proof` parameter to all API calls to verify that the access tokens are coming from a valid app.
73You can make this happen automatically by calling `graph.setAppSecret(app_secret)`, which will be used on
74all calls to generate the `appsecret_proof` hash that is sent to Facebook. Make sure you also set the
75access token for the user via `graph.setAccessToken`.
76
77## Extending access token expiration time
78
79If you want to [extend the expiration time](http://developers.facebook.com/docs/facebook-login/access-tokens/#extending) of your short-living access token, you may use `extendAccessToken` method as it is shown below:
80
81```js
82 // extending static access token
83 graph.extendAccessToken({
84 "client_id": conf.client_id
85 , "client_secret": conf.client_secret
86 }, function (err, facebookRes) {
87 console.log(facebookRes);
88 });
89
90 // extending specific access token
91 graph.extendAccessToken({
92 "access_token": client_access_token
93 , "client_id": conf.client_id
94 , "client_secret": conf.client_secret
95 }, function (err, facebookRes) {
96 console.log(facebookRes);
97 });
98
99
100```
101
102
103## How requests are made
104All calls are made using the [request](https://github.com/mikeal/request) nodejs module
105__Why?__ something to do with wheels and re-invention.
106
107Request options are directly mapped and can be set like so:
108
109```js
110var options = {
111 timeout: 3000
112 , pool: { maxSockets: Infinity }
113 , headers: { connection: "keep-alive" }
114};
115
116graph
117 .setOptions(options)
118 .get("zuck", function(err, res) {
119 console.log(res); // { id: '4', name: 'Mark Zuckerberg'... }
120 });
121```
122
123Possible options can be found on the [request github page](https://github.com/mikeal/request)
124
125`followRedirect` cannot be overriden and has a default value of `false`
126`encoding` will have `utf-8` as default if nothing is set
127
128### Pagination
129Pagination in Facebook is done either with a `cursor` or a `next` url to call.
130To simplify the fbgraph API, it's possible to use a fully constructed URL in order to get
131the next page. See the following example:
132
133```js
134// note: you might want to prevent the callback hell :)
135graph.get('likes', {limit: 2, access_token: "foobar"}, function(err, res) {
136 if(res.paging && res.paging.next) {
137 graph.get(res.paging.next, function(err, res) {
138 // page 2
139 });
140 }
141});
142```
143
144## Read data from the Graph Api
145
146```js
147graph.get("zuck", function(err, res) {
148 console.log(res); // { id: '4', name: 'Mark Zuckerberg'... }
149});
150```
151
152params in the `url`
153
154```js
155graph.get("zuck?fields=picture", function(err, res) {
156 console.log(res); // { picture: 'http://profile.ak.fbcdn.net/'... }
157});
158```
159
160params as an `object`
161
162```js
163var params = { fields: "picture" };
164
165graph.get("zuck", params, function(err, res) {
166 console.log(res); // { picture: "http://profile.ak.fbcdn.net/..." }
167});
168```
169
170GraphApi calls that __redirect__ directly to an image
171will return a `json` response with relevant fields
172
173```js
174graph.get("/zuck/picture", function(err, res) {
175 console.log(res); // { image: true, location: "http://profile.ak.fb..." }
176});
177```
178
179## Search data from the Graph Api
180
181Search for public posts that contain __brogramming__
182
183```js
184var searchOptions = {
185 q: "brogramming"
186 , type: "post"
187};
188
189graph.search(searchOptions, function(err, res) {
190 console.log(res); // {data: [{id: xxx, from: ...}, {id: xxx, from: ...}]}
191});
192```
193
194## Publish data to the Graph Api
195All publish requests will require an `access token`
196
197only needs to be set once
198
199```js
200graph.setAccessToken(accessToken);
201```
202
203
204
205Post a message on the user's wall
206
207```js
208var wallPost = {
209 message: "I'm gonna come at you like a spider monkey, chip!"
210};
211
212graph.post("/feed", wallPost, function(err, res) {
213 // returns the post id
214 console.log(res); // { id: xxxxx}
215});
216```
217
218## Delete a Graph object
219
220To delete a graph object, provide an `object id` and the
221response will return `{data: true}` or `{data:false}`
222
223```js
224graph.del(postID, function(err, res) {
225 console.log(res); // {data:true}/{data:false}
226});
227```
228
229## Performing a batch request
230
231[Batching](https://developers.facebook.com/docs/graph-api/making-multiple-requests) allows you to pass instructions for several operations in a single HTTP request.
232
233```js
234graph.batch([
235 {
236 method: "GET",
237 relative_url: "me" // Get the current user's profile information
238 },
239 {
240 method: "GET",
241 relative_url: "me/friends?limit=50" // Get the first 50 friends of the current user
242 }
243], function(err, res) {
244 console.log(res);
245 // [
246 // {
247 // "code": 200,
248 // "headers":[
249 // {"name": "Content-Type", "value": "text/javascript; charset=UTF-8"}
250 // ],
251 // "body": "{\"id\":\"…\"}"
252 // },
253 // {
254 // "code": 200,
255 // "headers":[
256 // {"name": "Content-Type", "value": "text/javascript; charset=UTF-8"}
257 // ],
258 // "body":"{\"data\": [{…}]}"
259 // }
260 // ]
261});
262```
263
264## Performing a FQL query
265
266A single FQL query is done by sending a query as a string
267
268```js
269var query = "SELECT name FROM user WHERE uid = me()";
270
271graph.fql(query, function(err, res) {
272 console.log(res); // { data: [ { name: 'Ricky Bobby' } ] }
273});
274```
275
276You can specify additional options by adding a JSON object
277```js
278var query = "SELECT name FROM user WHERE uid = me()";
279var options = {access_token: "foobar"};
280
281graph.fql(query, options, function(err, res) {
282 console.log(res); // { data: [ { name: 'Ricky Bobby' } ] }
283});
284```
285
286## Performing a FQL Multi-Query
287
288FQL Multi-Queries are done by sending in an object containing the separate queries
289
290```js
291var query = {
292 name: "SELECT name FROM user WHERE uid = me()"
293 , permissions: "SELECT email, user_about_me, user_birthday FROM permissions WHERE uid = me()"
294};
295
296graph.fql(query, function(err, res) {
297 console.log(res);
298 // { data: [
299 // { name: 'name', fql_result_set: [{name: 'Ricky Bobby'}] },
300 // { name: 'permissions', fql_result_set: [{email: 1, user_about_me: 1...}] }
301 // ]}
302});
303```
304
305## Rockin' it on an Express App
306
307This example assumes that you have a link on the main page `/` that points to `/auth/facebook`.
308The user will click this link and get into the facebook authorization flow ( if the user hasn't already connected)
309After `authorizing` the app the user will be redirected to `/UserHasLoggedIn`
310
311```js
312/**
313 * Module dependencies.
314 */
315
316var express = require('express')
317 , graph = require('fbgraph')
318 , app = module.exports = express.createServer();
319
320// this should really be in a config file!
321var conf = {
322 client_id: 'YOUR FACEBOOK APP ID'
323 , client_secret: 'YOU FACEBOOK APP SECRET'
324 , scope: 'email, user_about_me, user_birthday, user_location, publish_stream'
325 , redirect_uri: 'http://localhost:3000/auth/facebook'
326};
327
328// Configuration
329
330app.configure(function(){
331 app.set('views', __dirname + '/views');
332 app.set('view engine', 'jade');
333 app.use(express.bodyParser());
334 app.use(express.methodOverride());
335 app.use(app.router);
336 app.use(express.static(__dirname + '/public'));
337});
338
339app.configure('development', function(){
340 app.use(express.errorHandler({ dumpExceptions: true, showStack: true }));
341});
342
343app.configure('production', function(){
344 app.use(express.errorHandler());
345});
346
347// Routes
348
349app.get('/', function(req, res){
350 res.render("index", { title: "click link to connect" });
351});
352
353app.get('/auth/facebook', function(req, res) {
354
355 // we don't have a code yet
356 // so we'll redirect to the oauth dialog
357 if (!req.query.code) {
358 var authUrl = graph.getOauthUrl({
359 "client_id": conf.client_id
360 , "redirect_uri": conf.redirect_uri
361 , "scope": conf.scope
362 });
363
364 if (!req.query.error) { //checks whether a user denied the app facebook login/permissions
365 res.redirect(authUrl);
366 } else { //req.query.error == 'access_denied'
367 res.send('access denied');
368 }
369 return;
370 }
371
372 // code is set
373 // we'll send that and get the access token
374 graph.authorize({
375 "client_id": conf.client_id
376 , "redirect_uri": conf.redirect_uri
377 , "client_secret": conf.client_secret
378 , "code": req.query.code
379 }, function (err, facebookRes) {
380 res.redirect('/UserHasLoggedIn');
381 });
382
383
384});
385
386
387// user gets sent here after being authorized
388app.get('/UserHasLoggedIn', function(req, res) {
389 res.render("index", { title: "Logged In" });
390});
391
392
393var port = process.env.PORT || 3000;
394app.listen(port, function() {
395 console.log("Express server listening on port %d", port);
396});
397
398```
399
400## Running tests
401
402 Before running the test suite, add your Facebook `appId` and `appSecret` to `tests/config.js`
403 This is needed to create `test users` and to get a test `access_token`
404
405 $ npm install
406 $ make test
407
408 _Tests might fail if the Facebook api has an issue._
409
410## License
411
412(The MIT License)
413
414Copyright (c) 2011 Cristiano Oliveira <ocean.cris@gmail.com>
415
416Permission is hereby granted, free of charge, to any person obtaining
417a copy of this software and associated documentation files (the
418'Software'), to deal in the Software without restriction, including
419without limitation the rights to use, copy, modify, merge, publish,
420distribute, sublicense, and/or sell copies of the Software, and to
421permit persons to whom the Software is furnished to do so, subject to
422the following conditions:
423
424The above copyright notice and this permission notice shall be
425included in all copies or substantial portions of the Software.
426
427THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
428EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
429MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
430IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
431CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
432TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
433SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.