koala 0.4 → 3.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.github/workflows/test.yml +32 -0
- data/.gitignore +9 -0
- data/.rspec +1 -0
- data/.yardopts +3 -0
- data/Gemfile +25 -0
- data/ISSUE_TEMPLATE +25 -0
- data/LICENSE +22 -0
- data/Manifest +32 -5
- data/PULL_REQUEST_TEMPLATE +11 -0
- data/Rakefile +12 -12
- data/changelog.md +781 -0
- data/code_of_conduct.md +74 -0
- data/koala.gemspec +28 -24
- data/lib/koala/api/batch_operation.rb +86 -0
- data/lib/koala/api/graph_api_methods.rb +504 -0
- data/lib/koala/api/graph_batch_api.rb +167 -0
- data/lib/koala/api/graph_collection.rb +129 -0
- data/lib/koala/api/graph_error_checker.rb +72 -0
- data/lib/koala/api.rb +159 -0
- data/lib/koala/configuration.rb +56 -0
- data/lib/koala/errors.rb +126 -0
- data/lib/koala/http_service/request.rb +133 -0
- data/lib/koala/http_service/response.rb +20 -0
- data/lib/koala/http_service/uploadable_io.rb +183 -0
- data/lib/koala/http_service.rb +108 -0
- data/lib/koala/oauth.rb +342 -0
- data/lib/koala/realtime_updates.rb +151 -0
- data/lib/koala/test_users.rb +189 -0
- data/lib/koala/utils.rb +41 -0
- data/lib/koala/version.rb +3 -0
- data/lib/koala.rb +51 -291
- data/readme.md +269 -21
- data/spec/cases/api_spec.rb +362 -0
- data/spec/cases/configuration_spec.rb +11 -0
- data/spec/cases/error_spec.rb +143 -0
- data/spec/cases/graph_api_batch_spec.rb +788 -0
- data/spec/cases/graph_api_spec.rb +76 -0
- data/spec/cases/graph_collection_spec.rb +192 -0
- data/spec/cases/graph_error_checker_spec.rb +147 -0
- data/spec/cases/http_service/request_spec.rb +250 -0
- data/spec/cases/http_service/response_spec.rb +24 -0
- data/spec/cases/http_service_spec.rb +280 -0
- data/spec/cases/koala_spec.rb +57 -0
- data/spec/cases/koala_test_spec.rb +5 -0
- data/spec/cases/oauth_spec.rb +647 -0
- data/spec/cases/realtime_updates_spec.rb +327 -0
- data/spec/cases/test_users_spec.rb +383 -0
- data/spec/cases/uploadable_io_spec.rb +266 -0
- data/spec/cases/utils_spec.rb +55 -0
- data/spec/fixtures/beach.jpg +0 -0
- data/spec/fixtures/cat.m4v +0 -0
- data/spec/fixtures/facebook_data.yml +63 -0
- data/spec/fixtures/mock_facebook_responses.yml +483 -0
- data/spec/fixtures/vcr_cassettes/app_test_accounts.yml +97 -0
- data/spec/fixtures/vcr_cassettes/friend_list_next_page.yml +121 -0
- data/spec/integration/graph_collection_spec.rb +24 -0
- data/spec/spec_helper.rb +25 -0
- data/spec/support/custom_matchers.rb +28 -0
- data/spec/support/graph_api_shared_examples.rb +534 -0
- data/spec/support/koala_test.rb +251 -0
- data/spec/support/mock_http_service.rb +140 -0
- data/spec/support/uploadable_io_shared_examples.rb +70 -0
- metadata +206 -62
- data/CHANGELOG +0 -24
- data/init.rb +0 -2
- data/lib/http_services.rb +0 -60
- data/test/facebook_data.yml +0 -5
- data/test/koala/facebook_no_access_token_tests.rb +0 -119
- data/test/koala/facebook_with_access_token_tests.rb +0 -106
- data/test/koala_tests.rb +0 -30
data/lib/koala.rb
CHANGED
|
@@ -1,307 +1,67 @@
|
|
|
1
|
-
|
|
1
|
+
# useful tools
|
|
2
2
|
require 'digest/md5'
|
|
3
|
-
|
|
4
|
-
# rubygems is required to support json, how facebook returns data
|
|
5
|
-
require 'rubygems'
|
|
6
3
|
require 'json'
|
|
7
4
|
|
|
8
|
-
# include
|
|
9
|
-
require '
|
|
5
|
+
# include koala modules
|
|
6
|
+
require 'koala/errors'
|
|
7
|
+
require 'koala/api'
|
|
8
|
+
require 'koala/api/graph_batch_api'
|
|
9
|
+
require 'koala/oauth'
|
|
10
|
+
require 'koala/realtime_updates'
|
|
11
|
+
require 'koala/test_users'
|
|
10
12
|
|
|
11
|
-
module
|
|
12
|
-
|
|
13
|
-
# Copyright 2010 Facebook
|
|
14
|
-
# Adapted from the Python library by Alex Koppel, Rafi Jacoby, and the team at Context Optional
|
|
15
|
-
#
|
|
16
|
-
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
17
|
-
# not use this file except in compliance with the License. You may obtain
|
|
18
|
-
# a copy of the License at
|
|
19
|
-
# http://www.apache.org/licenses/LICENSE-2.0
|
|
20
|
-
#
|
|
21
|
-
# Unless required by applicable law or agreed to in writing, software
|
|
22
|
-
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
23
|
-
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
24
|
-
# License for the specific language governing permissions and limitations
|
|
25
|
-
# under the License.
|
|
26
|
-
#
|
|
27
|
-
# This client library is designed to support the Graph API and the official
|
|
28
|
-
# Facebook JavaScript SDK, which is the canonical way to implement
|
|
29
|
-
# Facebook authentication. Read more about the Graph API at
|
|
30
|
-
# http://developers.facebook.com/docs/api. You can download the Facebook
|
|
31
|
-
# JavaScript SDK at http://github.com/facebook/connect-js/.
|
|
13
|
+
# HTTP module so we can communicate with Facebook
|
|
14
|
+
require 'koala/http_service'
|
|
32
15
|
|
|
33
|
-
|
|
16
|
+
# miscellaneous
|
|
17
|
+
require 'koala/configuration'
|
|
18
|
+
require 'koala/utils'
|
|
19
|
+
require 'koala/version'
|
|
20
|
+
require 'ostruct'
|
|
34
21
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
# for the API.
|
|
40
|
-
#
|
|
41
|
-
# The Graph API is made up of the objects in Facebook (e.g., people, pages,
|
|
42
|
-
# events, photos) and the connections between them (e.g., friends,
|
|
43
|
-
# photo tags, and event RSVPs). This client provides access to those
|
|
44
|
-
# primitive types in a generic way. For example, given an OAuth access
|
|
45
|
-
# token, this will fetch the profile of the active user and the list
|
|
46
|
-
# of the user's friends:
|
|
47
|
-
#
|
|
48
|
-
# graph = Facebook::GraphAPI.new(access_token)
|
|
49
|
-
# user = graph.get_object("me")
|
|
50
|
-
# friends = graph.get_connections(user["id"], "friends")
|
|
51
|
-
#
|
|
52
|
-
# You can see a list of all of the objects and connections supported
|
|
53
|
-
# by the API at http://developers.facebook.com/docs/reference/api/.
|
|
54
|
-
#
|
|
55
|
-
# You can obtain an access token via OAuth or by using the Facebook
|
|
56
|
-
# JavaScript SDK. See http://developers.facebook.com/docs/authentication/
|
|
57
|
-
# for details.
|
|
58
|
-
#
|
|
59
|
-
# If you are using the JavaScript SDK, you can use the
|
|
60
|
-
# Facebook::get_user_from_cookie() method below to get the OAuth access token
|
|
61
|
-
# for the active user from the cookie saved by the SDK.
|
|
62
|
-
|
|
63
|
-
# initialize with an access token
|
|
64
|
-
def initialize(access_token = nil)
|
|
65
|
-
@access_token = access_token
|
|
66
|
-
end
|
|
67
|
-
|
|
68
|
-
def get_object(id, args = {})
|
|
69
|
-
# Fetchs the given object from the graph.
|
|
70
|
-
request(id, args)
|
|
71
|
-
end
|
|
72
|
-
|
|
73
|
-
def get_objects(ids, args = {})
|
|
74
|
-
# Fetchs all of the given object from the graph.
|
|
75
|
-
# We return a map from ID to object. If any of the IDs are invalid,
|
|
76
|
-
# we raise an exception.
|
|
77
|
-
request("", args.merge("ids" => ids.join(",")))
|
|
78
|
-
end
|
|
79
|
-
|
|
80
|
-
def get_connections(id, connection_name, args = {})
|
|
81
|
-
# Fetchs the connections for given object.
|
|
82
|
-
request("#{id}/#{connection_name}", args)
|
|
83
|
-
end
|
|
84
|
-
|
|
85
|
-
def put_object(parent_object, connection_name, args = {})
|
|
86
|
-
# Writes the given object to the graph, connected to the given parent.
|
|
87
|
-
#
|
|
88
|
-
# For example,
|
|
89
|
-
#
|
|
90
|
-
# graph.put_object("me", "feed", :message => "Hello, world")
|
|
91
|
-
#
|
|
92
|
-
# writes "Hello, world" to the active user's wall. Likewise, this
|
|
93
|
-
# will comment on a the first post of the active user's feed:
|
|
94
|
-
#
|
|
95
|
-
# feed = graph.get_connections("me", "feed")
|
|
96
|
-
# post = feed["data"][0]
|
|
97
|
-
# graph.put_object(post["id"], "comments", :message => "First!")
|
|
98
|
-
#
|
|
99
|
-
# See http://developers.facebook.com/docs/api#publishing for all of
|
|
100
|
-
# the supported writeable objects.
|
|
101
|
-
#
|
|
102
|
-
# Most write operations require extended permissions. For example,
|
|
103
|
-
# publishing wall posts requires the "publish_stream" permission. See
|
|
104
|
-
# http://developers.facebook.com/docs/authentication/ for details about
|
|
105
|
-
# extended permissions.
|
|
22
|
+
module Koala
|
|
23
|
+
# A Ruby client library for the Facebook Platform.
|
|
24
|
+
# See http://github.com/arsduo/koala/wiki for a general introduction to Koala
|
|
25
|
+
# and the Graph API.
|
|
106
26
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
# profile_id is specified.
|
|
116
|
-
#
|
|
117
|
-
# attachment adds a structured attachment to the status message being
|
|
118
|
-
# posted to the Wall. It should be a dictionary of the form:
|
|
119
|
-
#
|
|
120
|
-
# {"name": "Link name"
|
|
121
|
-
# "link": "http://www.example.com/",
|
|
122
|
-
# "caption": "{*actor*} posted a new review",
|
|
123
|
-
# "description": "This is a longer description of the attachment",
|
|
124
|
-
# "picture": "http://www.example.com/thumbnail.jpg"}
|
|
27
|
+
# Making HTTP requests
|
|
28
|
+
class << self
|
|
29
|
+
# Control which HTTP service framework Koala uses.
|
|
30
|
+
# Primarily used to switch between the mock-request framework used in testing
|
|
31
|
+
# and the live framework used in real life (and live testing).
|
|
32
|
+
# In theory, you could write your own HTTPService module if you need different functionality,
|
|
33
|
+
# but since the switch to {https://github.com/arsduo/koala/wiki/HTTP-Services Faraday} almost all such goals can be accomplished with middleware.
|
|
34
|
+
attr_accessor :http_service
|
|
125
35
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
def put_comment(object_id, message)
|
|
130
|
-
# Writes the given comment on the given post.
|
|
131
|
-
self.put_object(object_id, "comments", {:message => message})
|
|
132
|
-
end
|
|
133
|
-
|
|
134
|
-
def put_like(object_id)
|
|
135
|
-
# Likes the given post.
|
|
136
|
-
self.put_object(object_id, "likes")
|
|
36
|
+
def configure
|
|
37
|
+
yield config
|
|
137
38
|
end
|
|
138
|
-
|
|
139
|
-
def delete_object(id)
|
|
140
|
-
# Deletes the object with the given ID from the graph.
|
|
141
|
-
request(id, {}, "delete")
|
|
142
|
-
end
|
|
143
|
-
|
|
144
|
-
def search(search_terms, args = {})
|
|
145
|
-
# Searches for a given term
|
|
146
|
-
request("search", args.merge({:q => search_terms}))
|
|
147
|
-
end
|
|
148
|
-
|
|
149
|
-
def request(path, args = {}, verb = "get")
|
|
150
|
-
# Fetches the given path in the Graph API.
|
|
151
|
-
args["access_token"] = @access_token if @access_token
|
|
152
|
-
|
|
153
|
-
# make the request via the provided service
|
|
154
|
-
result = make_request(path, args, verb)
|
|
155
|
-
|
|
156
|
-
# Facebook sometimes sends results like "true" and "false", which aren't strictly object
|
|
157
|
-
# and cause JSON.parse to fail
|
|
158
|
-
# so we account for that
|
|
159
|
-
response = JSON.parse("[#{result}]")[0]
|
|
160
39
|
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
response
|
|
167
|
-
end
|
|
168
|
-
|
|
169
|
-
# set up the http service used to make requests
|
|
170
|
-
# you can use your own (for HTTParty, etc.) by calling Koala::API.http_service = YourModule
|
|
171
|
-
def self.http_service=(service)
|
|
172
|
-
self.send(:include, service)
|
|
40
|
+
# Allows you to control various Koala configuration options.
|
|
41
|
+
# NOTE: this is not currently threadsafe.
|
|
42
|
+
# See Koala::Configuration.
|
|
43
|
+
def config
|
|
44
|
+
@config ||= Configuration.new
|
|
173
45
|
end
|
|
174
|
-
|
|
175
|
-
#
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
Koala::GraphAPI.http_service = TyphoeusService
|
|
179
|
-
rescue LoadError
|
|
180
|
-
Koala::GraphAPI.http_service = NetHTTPService
|
|
181
|
-
end
|
|
182
|
-
end
|
|
183
|
-
|
|
184
|
-
class GraphAPIError < Exception
|
|
185
|
-
attr_accessor :code
|
|
186
|
-
def initialize(code, message)
|
|
187
|
-
super(message)
|
|
188
|
-
self.code = code
|
|
46
|
+
|
|
47
|
+
# Used for testing.
|
|
48
|
+
def reset_config
|
|
49
|
+
@config = nil
|
|
189
50
|
end
|
|
190
51
|
end
|
|
191
|
-
|
|
192
|
-
class OAuth
|
|
193
|
-
def initialize(app_id, app_secret, oauth_callback_url = nil)
|
|
194
|
-
@app_id = app_id
|
|
195
|
-
@app_secret = app_secret
|
|
196
|
-
@oauth_callback_url = oauth_callback_url
|
|
197
|
-
end
|
|
198
|
-
|
|
199
|
-
def get_user_from_cookie(cookie_hash)
|
|
200
|
-
# Parses the cookie set by the official Facebook JavaScript SDK.
|
|
201
|
-
#
|
|
202
|
-
# cookies should be a dictionary-like object mapping cookie names to
|
|
203
|
-
# cookie values.
|
|
204
|
-
#
|
|
205
|
-
# If the user is logged in via Facebook, we return a dictionary with the
|
|
206
|
-
# keys "uid" and "access_token". The former is the user's Facebook ID,
|
|
207
|
-
# and the latter can be used to make authenticated requests to the Graph API.
|
|
208
|
-
# If the user is not logged in, we return None.
|
|
209
|
-
#
|
|
210
|
-
# Download the official Facebook JavaScript SDK at
|
|
211
|
-
# http://github.com/facebook/connect-js/. Read more about Facebook
|
|
212
|
-
# authentication at http://developers.facebook.com/docs/authentication/.
|
|
213
|
-
|
|
214
|
-
if fb_cookie = cookie_hash["fbs_" + @app_id.to_s]
|
|
215
|
-
# remove the opening/closing quote
|
|
216
|
-
fb_cookie = fb_cookie.gsub(/\"/, "")
|
|
217
|
-
|
|
218
|
-
# since we no longer get individual cookies, we have to separate out the components ourselves
|
|
219
|
-
components = {}
|
|
220
|
-
fb_cookie.split("&").map {|param| param = param.split("="); components[param[0]] = param[1]}
|
|
221
|
-
|
|
222
|
-
auth_string = components.keys.sort.collect {|a| a == "sig" ? nil : "#{a}=#{components[a]}"}.reject {|a| a.nil?}.join("")
|
|
223
|
-
sig = Digest::MD5.hexdigest(auth_string + @app_secret)
|
|
224
52
|
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
permissions = options[:permissions]
|
|
232
|
-
scope = permissions ? "&scope=#{permissions.is_a?(Array) ? permissions.join(",") : permissions}" : ""
|
|
53
|
+
# @private
|
|
54
|
+
# Switch the HTTP service -- mostly used for testing.
|
|
55
|
+
def self.http_service=(service)
|
|
56
|
+
# if it's a real http_service, use it
|
|
57
|
+
@http_service = service
|
|
58
|
+
end
|
|
233
59
|
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
def url_for_access_token(code, callback = @oauth_callback_url)
|
|
239
|
-
# Creates the URL for the token corresponding to a given code generated by Facebook
|
|
240
|
-
"https://#{FACEBOOK_GRAPH_SERVER}/oauth/access_token?client_id=#{@app_id}&redirect_uri=#{callback}&client_secret=#{@app_secret}&code=#{code}"
|
|
241
|
-
end
|
|
242
|
-
|
|
243
|
-
# for more details and up to date information, see http://developers.facebook.com/docs/authentication/permissions
|
|
244
|
-
def self.all_permissions
|
|
245
|
-
USER_PERMISSIONS.concat(FRIEND_PERMISSIONS)
|
|
246
|
-
end
|
|
247
|
-
|
|
248
|
-
USER_PERMISSIONS = [
|
|
249
|
-
# PUBLISHING
|
|
250
|
-
"publish_stream", # Enables your application to post content, comments, and likes to a user's stream and to the streams of the user's friends, without prompting the user each time.
|
|
251
|
-
"create_event", # Enables your application to create and modify events on the user's behalf
|
|
252
|
-
"rsvp_event", # Enables your application to RSVP to events on the user's behalf
|
|
253
|
-
"sms", # Enables your application to send messages to the user and respond to messages from the user via text message
|
|
254
|
-
"offline_access", # Enables your application to perform authorized requests on behalf of the user at any time (e.g. permanent access token)
|
|
255
|
-
|
|
256
|
-
# DATA ACCESS
|
|
257
|
-
"email", # Provides access to the user's primary email address in the email property
|
|
258
|
-
"read_stream", # Provides access to all the posts in the user's News Feed and enables your application to perform searches against the user's News Feed
|
|
259
|
-
"user_about_me", # Provides access to the "About Me" section of the profile in the about property
|
|
260
|
-
"user_activities", # Provides access to the user's list of activities as the activities connection
|
|
261
|
-
"user_birthday", # Provides access to the full birthday with year as the birthday_date property
|
|
262
|
-
"user_education_history", # Provides access to education history as the education property
|
|
263
|
-
"user_events", # Provides access to the list of events the user is attending as the events connection
|
|
264
|
-
"user_groups", # Provides access to the list of groups the user is a member of as the groups connection
|
|
265
|
-
"user_hometown", # Provides access to the user's hometown in the hometown property
|
|
266
|
-
"user_interests", # Provides access to the user's list of interests as the interests connection
|
|
267
|
-
"user_likes", # Provides access to the list of all of the pages the user has liked as the likes connection
|
|
268
|
-
"user_location", # Provides access to the user's current location as the current_location property
|
|
269
|
-
"user_notes", # Provides access to the user's notes as the notes connection
|
|
270
|
-
"user_online_presence", # Provides access to the user's online/offline presence
|
|
271
|
-
"user_photo_video_tags", # Provides access to the photos the user has been tagged in as the photos connection
|
|
272
|
-
"user_photos", # Provides access to the photos the user has uploaded
|
|
273
|
-
"user_relationships", # Provides access to the user's family and personal relationships and relationship status
|
|
274
|
-
"user_religion_politics", # Provides access to the user's religious and political affiliations
|
|
275
|
-
"user_status", # Provides access to the user's most recent status message
|
|
276
|
-
"user_videos", # Provides access to the videos the user has uploaded
|
|
277
|
-
"user_website", # Provides access to the user's web site URL
|
|
278
|
-
"user_work_history", # Provides access to work history as the work property
|
|
279
|
-
"read_friendlists", # Provides read access to the user's friend lists
|
|
280
|
-
"read_requests" # Provides read access to the user's friend requests
|
|
281
|
-
]
|
|
282
|
-
|
|
283
|
-
FRIEND_PERMISSIONS = [
|
|
284
|
-
# DATA ACCESS
|
|
285
|
-
"friends_about_me", # Provides access to the "About Me" section of the profile in the about property
|
|
286
|
-
"friends_activities", # Provides access to the user's list of activities as the activities connection
|
|
287
|
-
"friends_birthday", # Provides access to the full birthday with year as the birthday_date property
|
|
288
|
-
"friends_education_history", # Provides access to education history as the education property
|
|
289
|
-
"friends_events", # Provides access to the list of events the user is attending as the events connection
|
|
290
|
-
"friends_groups", # Provides access to the list of groups the user is a member of as the groups connection
|
|
291
|
-
"friends_hometown", # Provides access to the user's hometown in the hometown property
|
|
292
|
-
"friends_interests", # Provides access to the user's list of interests as the interests connection
|
|
293
|
-
"friends_likes", # Provides access to the list of all of the pages the user has liked as the likes connection
|
|
294
|
-
"friends_location", # Provides access to the user's current location as the current_location property
|
|
295
|
-
"friends_notes", # Provides access to the user's notes as the notes connection
|
|
296
|
-
"friends_online_presence", # Provides access to the user's online/offline presence
|
|
297
|
-
"friends_photo_video_tags", # Provides access to the photos the user has been tagged in as the photos connection
|
|
298
|
-
"friends_photos", # Provides access to the photos the user has uploaded
|
|
299
|
-
"friends_relationships", # Provides access to the user's family and personal relationships and relationship status
|
|
300
|
-
"friends_religion_politics", # Provides access to the user's religious and political affiliations
|
|
301
|
-
"friends_status", # Provides access to the user's most recent status message
|
|
302
|
-
"friends_videos", # Provides access to the videos the user has uploaded
|
|
303
|
-
"friends_website", # Provides access to the user's web site URL
|
|
304
|
-
"friends_work_history" # Provides access to work history as the work property
|
|
305
|
-
]
|
|
60
|
+
# An convenenient alias to Koala.http_service.make_request.
|
|
61
|
+
def self.make_request(path, args, verb, options = {})
|
|
62
|
+
http_service.make_request(HTTPService::Request.new(path: path, args: args, verb: verb, options: options))
|
|
306
63
|
end
|
|
307
|
-
|
|
64
|
+
|
|
65
|
+
# we use Faraday as our main service, with mock as the other main one
|
|
66
|
+
self.http_service = HTTPService
|
|
67
|
+
end
|
data/readme.md
CHANGED
|
@@ -1,29 +1,277 @@
|
|
|
1
|
-
|
|
1
|
+
Koala [](https://rubygems.org/gems/koala) [](http://travis-ci.org/arsduo/koala) [](https://codeclimate.com/github/arsduo/koala) [](https://codeclimate.com/github/arsduo/koala)
|
|
2
2
|
====
|
|
3
|
+
[Koala](http://github.com/arsduo/koala) is a Facebook library for Ruby, supporting the Graph API (including the batch requests and photo uploads), the Marketing API, the Atlas API, realtime updates, test users, and OAuth validation. We wrote Koala with four goals:
|
|
3
4
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
about the Graph API at [http://developers.facebook.com/docs/api](http://developers.facebook.com/docs/api).
|
|
5
|
+
* Lightweight: Koala should be as light and simple as Facebook’s own libraries, providing API accessors and returning simple JSON.
|
|
6
|
+
* Fast: Koala should, out of the box, be quick. Out of the box, we use Facebook's faster read-only servers when possible and if available, the Typhoeus gem to make snappy Facebook requests. Of course, that brings us to our next topic:
|
|
7
|
+
* Flexible: Koala should be useful to everyone, regardless of their current configuration. We support all currently-supported Ruby versions (MRI 2.1-2.4) and Koala should work on JRuby and Rubinius.
|
|
8
|
+
* Tested: Koala should have complete test coverage, so you can rely on it. Our test coverage is complete and can be run against either mocked responses or the live Facebook servers; we're also on [Travis CI](http://travis-ci.org/arsduo/koala/).
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
**Found a bug? Interested in contributing?** Check out the Maintenance section below!
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
friends = graph.get_connections("me", "friends")
|
|
15
|
-
graph.put_object("me", "feed", :message => "I am writing on my wall!")
|
|
12
|
+
Installation
|
|
13
|
+
------------
|
|
16
14
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
module to use Facebook for login, parsing the cookie set by the JavaScript SDK
|
|
20
|
-
for logged in users.
|
|
15
|
+
**Koala 3.0 is out! There should be no significant changes** for most users. If you encounter any
|
|
16
|
+
problems, please file an issue and I'll take a look.
|
|
21
17
|
|
|
22
|
-
|
|
18
|
+
In Bundler:
|
|
19
|
+
```ruby
|
|
20
|
+
gem "koala"
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Otherwise:
|
|
24
|
+
```bash
|
|
25
|
+
[sudo|rvm] gem install koala
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Configuration
|
|
29
|
+
-------------
|
|
30
|
+
|
|
31
|
+
Most applications will only use one application configuration. Rather than having to provide that
|
|
32
|
+
value every time, you can configure Koala to use global settings:
|
|
33
|
+
|
|
34
|
+
```ruby
|
|
35
|
+
# In Rails, you could put this in config/initializers/koala.rb
|
|
36
|
+
Koala.configure do |config|
|
|
37
|
+
config.access_token = MY_TOKEN
|
|
38
|
+
config.app_access_token = MY_APP_ACCESS_TOKEN
|
|
39
|
+
config.app_id = MY_APP_ID
|
|
40
|
+
config.app_secret = MY_APP_SECRET
|
|
41
|
+
# See Koala::Configuration for more options, including details on how to send requests through
|
|
42
|
+
# your own proxy servers.
|
|
43
|
+
end
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
**Note**: this is not currently threadsafe. (PRs welcome as long as they support both threaded and
|
|
47
|
+
non-threaded configuration.)
|
|
48
|
+
|
|
49
|
+
Graph API
|
|
50
|
+
---------
|
|
51
|
+
|
|
52
|
+
The Graph API is the interface to Facebook's data. Using it with Koala is quite straightforward.
|
|
53
|
+
First, you'll need an access token, which you can get through Facebook's [Graph API
|
|
54
|
+
Explorer](https://developers.facebook.com/tools/explorer) (click on 'Get Access Token').
|
|
55
|
+
|
|
56
|
+
Then, go exploring:
|
|
57
|
+
|
|
58
|
+
```ruby
|
|
59
|
+
require 'koala'
|
|
60
|
+
|
|
61
|
+
# access_token and other values aren't required if you set the defaults as described above
|
|
62
|
+
@graph = Koala::Facebook::API.new(access_token)
|
|
63
|
+
|
|
64
|
+
profile = @graph.get_object("me")
|
|
65
|
+
friends = @graph.get_connections("me", "friends")
|
|
66
|
+
@graph.put_connections("me", "feed", message: "I am writing on my wall!")
|
|
67
|
+
|
|
68
|
+
# Three-part queries are easy too!
|
|
69
|
+
@graph.get_connections("me", "mutualfriends/#{friend_id}")
|
|
70
|
+
|
|
71
|
+
# You can use the Timeline API:
|
|
72
|
+
# (see https://developers.facebook.com/docs/beta/opengraph/tutorial/)
|
|
73
|
+
@graph.put_connections("me", "namespace:action", object: object_url)
|
|
74
|
+
|
|
75
|
+
# For extra security (recommended), you can provide an appsecret parameter,
|
|
76
|
+
# tying your access tokens to your app secret.
|
|
77
|
+
# (See https://developers.facebook.com/docs/reference/api/securing-graph-api/
|
|
78
|
+
|
|
79
|
+
# You may need to turn on 'Require proof on all calls' in the advanced section
|
|
80
|
+
# of your app's settings when doing this.
|
|
81
|
+
@graph = Koala::Facebook::API.new(access_token, app_secret)
|
|
82
|
+
|
|
83
|
+
# Facebook is now versioning their API. # If you don't specify a version, Facebook
|
|
84
|
+
# will default to the oldest version your app is allowed to use.
|
|
85
|
+
# See https://developers.facebook.com/docs/apps/versions for more information.
|
|
86
|
+
#
|
|
87
|
+
# You can specify version either globally:
|
|
88
|
+
Koala.config.api_version = "v2.0"
|
|
89
|
+
# or on a per-request basis
|
|
90
|
+
@graph.get_object("me", {}, api_version: "v2.0")
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
The response of most requests is the JSON data returned from the Facebook servers as a Hash.
|
|
94
|
+
|
|
95
|
+
When retrieving data that returns an array of results (for example, when calling `API#get_connections` or `API#search`)
|
|
96
|
+
a GraphCollection object will be returned, which makes it easy to page through the results:
|
|
97
|
+
|
|
98
|
+
```ruby
|
|
99
|
+
# Returns the feed items for the currently logged-in user as a GraphCollection
|
|
100
|
+
feed = @graph.get_connections("me", "feed")
|
|
101
|
+
feed.each {|f| do_something_with_item(f) } # it's a subclass of Array
|
|
102
|
+
next_feed = feed.next_page
|
|
103
|
+
|
|
104
|
+
# You can also get an array describing the URL for the next page: [path, arguments]
|
|
105
|
+
# This is useful for storing page state across multiple browser requests
|
|
106
|
+
next_page_params = feed.next_page_params
|
|
107
|
+
page = @graph.get_page(next_page_params)
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
You can also make multiple calls at once using Facebook's batch API:
|
|
111
|
+
```ruby
|
|
112
|
+
# Returns an array of results as if they were called non-batch
|
|
113
|
+
@graph.batch do |batch_api|
|
|
114
|
+
batch_api.get_object('me')
|
|
115
|
+
batch_api.put_wall_post('Making a post in a batch.')
|
|
116
|
+
end
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
You can pass a "post-processing" block to each of Koala's Graph API methods. This is handy for two reasons:
|
|
120
|
+
|
|
121
|
+
1. You can modify the result returned by the Graph API method:
|
|
122
|
+
|
|
123
|
+
education = @graph.get_object("me") { |data| data['education'] }
|
|
124
|
+
# returned value only contains the "education" portion of the profile
|
|
125
|
+
|
|
126
|
+
2. You can consume the data in place which is particularly useful in the batch case, so you don't have to pull
|
|
127
|
+
the results apart from a long list of array entries:
|
|
128
|
+
|
|
129
|
+
@graph.batch do |batch_api|
|
|
130
|
+
# Assuming you have database fields "about_me" and "photos"
|
|
131
|
+
batch_api.get_object('me') {|me| self.about_me = me }
|
|
132
|
+
batch_api.get_connections('me', 'photos') {|photos| self.photos = photos }
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
Check out the wiki for more details and examples.
|
|
136
|
+
|
|
137
|
+
App Access Tokens
|
|
23
138
|
-----
|
|
24
139
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
140
|
+
You get your application's own access token, which can be used without a user session for subscriptions and certain other requests:
|
|
141
|
+
```ruby
|
|
142
|
+
@oauth = Koala::Facebook::OAuth.new(app_id, app_secret, callback_url)
|
|
143
|
+
@oauth.get_app_access_token
|
|
144
|
+
```
|
|
145
|
+
For those building apps on Facebook, parsing signed requests is simple:
|
|
146
|
+
```ruby
|
|
147
|
+
@oauth.parse_signed_request(signed_request_string)
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
The OAuth class has additional methods that may occasionally be useful.
|
|
151
|
+
|
|
152
|
+
Real-time Updates
|
|
153
|
+
-----------------
|
|
154
|
+
|
|
155
|
+
Sometimes, reaching out to Facebook is a pain -- let it reach out to you instead. The Graph API allows your application to subscribe to real-time updates for certain objects in the graph; check the [official Facebook documentation](http://developers.facebook.com/docs/api/realtime) for more details on what objects you can subscribe to and what limitations may apply.
|
|
156
|
+
|
|
157
|
+
Koala makes it easy to interact with your applications using the RealtimeUpdates class:
|
|
158
|
+
```ruby
|
|
159
|
+
# This class also supports the defaults as described above
|
|
160
|
+
@updates = Koala::Facebook::RealtimeUpdates.new(app_id: app_id, secret: secret)
|
|
161
|
+
```
|
|
162
|
+
You can do just about anything with your real-time update subscriptions using the RealtimeUpdates class:
|
|
163
|
+
```ruby
|
|
164
|
+
# Add/modify a subscription to updates for when the first_name or last_name fields of any of your users is changed
|
|
165
|
+
@updates.subscribe("user", "first_name, last_name", callback_url, verify_token)
|
|
166
|
+
|
|
167
|
+
# Get an array of your current subscriptions (one hash for each object you've subscribed to)
|
|
168
|
+
@updates.list_subscriptions
|
|
169
|
+
|
|
170
|
+
# Unsubscribe from updates for an object
|
|
171
|
+
@updates.unsubscribe("user")
|
|
172
|
+
```
|
|
173
|
+
And to top it all off, RealtimeUpdates provides a static method to respond to Facebook servers' verification of your callback URLs:
|
|
174
|
+
```ruby
|
|
175
|
+
# Returns the hub.challenge parameter in params if the verify token in params matches verify_token
|
|
176
|
+
Koala::Facebook::RealtimeUpdates.meet_challenge(params, your_verify_token)
|
|
177
|
+
```
|
|
178
|
+
For more information about meet_challenge and the RealtimeUpdates class, check out the Real-Time Updates page on the wiki.
|
|
179
|
+
|
|
180
|
+
Rate limits
|
|
181
|
+
-----------
|
|
182
|
+
|
|
183
|
+
We support Facebook rate limit informations as defined here: [https://developers.facebook.com/docs/graph-api/overview/rate-limiting/](https://developers.facebook.com/docs/graph-api/overview/rate-limiting/)
|
|
184
|
+
|
|
185
|
+
The information is available either via the `Facebook::APIError`:
|
|
186
|
+
|
|
187
|
+
```ruby
|
|
188
|
+
error.fb_buc_usage
|
|
189
|
+
error.fb_ada_usage
|
|
190
|
+
error.fb_app_usage
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
Or with the rate_limit_hook:
|
|
194
|
+
|
|
195
|
+
```ruby
|
|
196
|
+
# App level configuration
|
|
197
|
+
|
|
198
|
+
Koala.configure do |config|
|
|
199
|
+
config.rate_limit_hook = ->(limits) {
|
|
200
|
+
limits["x-app-usage"] # {"call_count"=>0, "total_cputime"=>0, "total_time"=>0}
|
|
201
|
+
limits["x-ad-account-usage"] # {"acc_id_util_pct"=>9.67}
|
|
202
|
+
limits["x-business-use-case-usage"] # {"123456789012345"=>[{"type"=>"messenger", "call_count"=>1, "total_cputime"=>1, "total_time"=>1, "estimated_time_to_regain_access"=>0}]}
|
|
203
|
+
}
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
# Per API configuration
|
|
207
|
+
|
|
208
|
+
Koala::Facebook::API.new('', '', ->(limits) {})
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
Test Users
|
|
212
|
+
----------
|
|
213
|
+
|
|
214
|
+
We also support the test users API, allowing you to conjure up fake users and command them to do your bidding using the Graph API:
|
|
215
|
+
```ruby
|
|
216
|
+
# This class also supports the defaults as described above
|
|
217
|
+
@test_users = Koala::Facebook::TestUsers.new(app_id: id, secret: secret)
|
|
218
|
+
user = @test_users.create(is_app_installed, desired_permissions)
|
|
219
|
+
user_graph_api = Koala::Facebook::API.new(user["access_token"])
|
|
220
|
+
# or, if you want to make a whole community:
|
|
221
|
+
@test_users.create_network(network_size, is_app_installed, common_permissions)
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
Talking to Facebook
|
|
225
|
+
-------------------
|
|
226
|
+
|
|
227
|
+
Koala uses Faraday to make HTTP requests, which means you have complete control over how your app makes HTTP requests to Facebook. You can set Faraday options globally or pass them in on a per-request (or both):
|
|
228
|
+
```ruby
|
|
229
|
+
# Set an SSL certificate to avoid Net::HTTP errors
|
|
230
|
+
Koala.http_service.http_options = {
|
|
231
|
+
ssl: { ca_path: "/etc/ssl/certs" }
|
|
232
|
+
}
|
|
233
|
+
# or on a per-request basis
|
|
234
|
+
@api.get_object(id, args_hash, { request: { timeout: 10 } })
|
|
235
|
+
```
|
|
236
|
+
The <a href="https://github.com/arsduo/koala/wiki/HTTP-Services">HTTP Services wiki page</a> has more information on what options are available, as well as on how to configure your own Faraday middleware stack (for instance, to implement request logging).
|
|
237
|
+
|
|
238
|
+
See examples, ask questions
|
|
239
|
+
---------------------------
|
|
240
|
+
|
|
241
|
+
Some resources to help you as you play with Koala and the Graph API:
|
|
242
|
+
|
|
243
|
+
* Complete Koala documentation <a href="https://github.com/arsduo/koala/wiki">on the wiki</a>
|
|
244
|
+
* Facebook's <a href="http://facebook.stackoverflow.com/">Stack Overflow site</a> is a stupendous place to ask questions, filled with people who will help you figure out what's up with the Facebook API.
|
|
245
|
+
* Facebook's <a href="http://developers.facebook.com/tools/explorer/">Graph API Explorer</a>, where you can play with the Graph API in your browser
|
|
246
|
+
|
|
247
|
+
Testing
|
|
248
|
+
-------
|
|
249
|
+
|
|
250
|
+
Unit tests are provided for all of Koala's methods. By default, these tests run against mock responses and hence are ready out of the box:
|
|
251
|
+
```bash
|
|
252
|
+
# From anywhere in the project directory:
|
|
253
|
+
bundle exec rake spec
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
You can also run live tests against Facebook's servers:
|
|
257
|
+
```bash
|
|
258
|
+
# Again from anywhere in the project directory:
|
|
259
|
+
LIVE=true bundle exec rake spec
|
|
260
|
+
# you can also test against Facebook's beta tier
|
|
261
|
+
LIVE=true BETA=true bundle exec rake spec
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
By default, the live tests are run against test users, so you can run them as frequently as you want. If you want to run them against a real user, however, you can fill in the OAuth token, code, and access\_token values in spec/fixtures/facebook_data.yml. See the wiki for more details.
|
|
265
|
+
|
|
266
|
+
Maintenance
|
|
267
|
+
-----------
|
|
268
|
+
|
|
269
|
+
_Pull requests_: Koala exists as it does thanks to the amazing support and work of community members of all
|
|
270
|
+
backgrounds and levels of experience. Pull requests are very welcome!
|
|
271
|
+
|
|
272
|
+
_Issues_: If you have any questions about the gem, found an issue in the Ruby code or
|
|
273
|
+
documentation, or have another question that isn't right for StackOverflow, just open an issue and fill out the template.
|
|
274
|
+
|
|
275
|
+
Please note that this project is released with a Contributor Code of Conduct. By participating in
|
|
276
|
+
this project you agree to abide by its terms. See
|
|
277
|
+
[code_of_conduct.md](https://github.com/arsduo/koala/blob/master/code_of_conduct.md) for more information.
|