koala 2.5.0 → 3.0.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.
Files changed (57) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +5 -3
  3. data/Gemfile +1 -1
  4. data/ISSUE_TEMPLATE +25 -0
  5. data/PULL_REQUEST_TEMPLATE +11 -0
  6. data/changelog.md +66 -4
  7. data/code_of_conduct.md +64 -12
  8. data/koala.gemspec +3 -0
  9. data/lib/koala/api/batch_operation.rb +3 -6
  10. data/lib/koala/api/{graph_api.rb → graph_api_methods.rb} +13 -102
  11. data/lib/koala/api/graph_batch_api.rb +112 -65
  12. data/lib/koala/api/graph_collection.rb +19 -12
  13. data/lib/koala/api/graph_error_checker.rb +1 -1
  14. data/lib/koala/api.rb +49 -25
  15. data/lib/koala/configuration.rb +49 -0
  16. data/lib/koala/errors.rb +1 -1
  17. data/lib/koala/http_service/multipart_request.rb +6 -10
  18. data/lib/koala/http_service/request.rb +135 -0
  19. data/lib/koala/http_service/response.rb +6 -4
  20. data/lib/koala/http_service/uploadable_io.rb +0 -4
  21. data/lib/koala/http_service.rb +18 -76
  22. data/lib/koala/oauth.rb +7 -7
  23. data/lib/koala/realtime_updates.rb +26 -21
  24. data/lib/koala/test_users.rb +9 -8
  25. data/lib/koala/version.rb +1 -1
  26. data/lib/koala.rb +6 -8
  27. data/readme.md +50 -109
  28. data/spec/cases/api_spec.rb +99 -69
  29. data/spec/cases/configuration_spec.rb +11 -0
  30. data/spec/cases/graph_api_batch_spec.rb +73 -42
  31. data/spec/cases/graph_api_spec.rb +15 -29
  32. data/spec/cases/graph_collection_spec.rb +47 -34
  33. data/spec/cases/graph_error_checker_spec.rb +6 -1
  34. data/spec/cases/http_service/request_spec.rb +242 -0
  35. data/spec/cases/http_service/response_spec.rb +24 -0
  36. data/spec/cases/http_service_spec.rb +102 -296
  37. data/spec/cases/koala_spec.rb +7 -5
  38. data/spec/cases/oauth_spec.rb +40 -1
  39. data/spec/cases/realtime_updates_spec.rb +51 -13
  40. data/spec/cases/test_users_spec.rb +56 -2
  41. data/spec/cases/uploadable_io_spec.rb +31 -31
  42. data/spec/fixtures/cat.m4v +0 -0
  43. data/spec/fixtures/facebook_data.yml +4 -6
  44. data/spec/fixtures/mock_facebook_responses.yml +29 -69
  45. data/spec/fixtures/vcr_cassettes/app_test_accounts.yml +97 -0
  46. data/spec/integration/graph_collection_spec.rb +8 -5
  47. data/spec/spec_helper.rb +2 -2
  48. data/spec/support/graph_api_shared_examples.rb +143 -336
  49. data/spec/support/koala_test.rb +8 -10
  50. data/spec/support/mock_http_service.rb +9 -9
  51. data/spec/support/uploadable_io_shared_examples.rb +4 -4
  52. metadata +31 -11
  53. data/.autotest +0 -12
  54. data/Guardfile +0 -6
  55. data/autotest/discover.rb +0 -1
  56. data/lib/koala/api/rest_api.rb +0 -135
  57. data/spec/support/rest_api_shared_examples.rb +0 -168
@@ -2,6 +2,7 @@ require 'faraday'
2
2
  require 'koala/http_service/multipart_request'
3
3
  require 'koala/http_service/uploadable_io'
4
4
  require 'koala/http_service/response'
5
+ require 'koala/http_service/request'
5
6
 
6
7
  module Koala
7
8
  module HTTPService
@@ -23,98 +24,46 @@ module Koala
23
24
  builder.adapter Faraday.default_adapter
24
25
  end
25
26
 
26
- # Default servers for Facebook. These are read into the config OpenStruct,
27
- # and can be overridden via Koala.config.
27
+ # Default server information for Facebook. These can be overridden by setting config values.
28
+ # See Koala.config.
28
29
  DEFAULT_SERVERS = {
29
30
  :graph_server => 'graph.facebook.com',
30
31
  :dialog_host => 'www.facebook.com',
31
- :rest_server => 'api.facebook.com',
32
- # certain Facebook services (beta, video) require you to access different
33
- # servers. If you're using your own servers, for instance, for a proxy,
34
- # you can change both the matcher and the replacement values.
35
- # So for instance, if you're talking to fbproxy.mycompany.com, you could
36
- # set up beta.fbproxy.mycompany.com for FB's beta tier, and set the
37
- # matcher to /\.fbproxy/ and the beta_replace to '.beta.fbproxy'.
38
32
  :host_path_matcher => /\.facebook/,
39
33
  :video_replace => '-video.facebook',
40
34
  :beta_replace => '.beta.facebook'
41
35
  }
42
36
 
43
- # The address of the appropriate Facebook server.
44
- #
45
- # @param options various flags to indicate which server to use.
46
- # @option options :rest_api use the old REST API instead of the Graph API
47
- # @option options :video use the server designated for video uploads
48
- # @option options :beta use the beta tier
49
- # @option options :use_ssl force https, even if not needed
50
- #
51
- # @return a complete server address with protocol
52
- def self.server(options = {})
53
- server = "#{options[:rest_api] ? Koala.config.rest_server : Koala.config.graph_server}"
54
- server.gsub!(Koala.config.host_path_matcher, Koala.config.video_replace) if options[:video]
55
- server.gsub!(Koala.config.host_path_matcher, Koala.config.beta_replace) if options[:beta]
56
- "#{options[:use_ssl] ? "https" : "http"}://#{server}"
57
- end
58
-
59
37
  # Makes a request directly to Facebook.
60
38
  # @note You'll rarely need to call this method directly.
61
39
  #
62
40
  # @see Koala::Facebook::API#api
63
41
  # @see Koala::Facebook::GraphAPIMethods#graph_call
64
- # @see Koala::Facebook::RestAPIMethods#rest_call
65
42
  #
66
- # @param path the server path for this request
67
- # @param args (see Koala::Facebook::API#api)
68
- # @param verb the HTTP method to use.
69
- # If not get or post, this will be turned into a POST request with the appropriate :method
70
- # specified in the arguments.
71
- # @param options (see Koala::Facebook::API#api)
43
+ # @param request a Koala::HTTPService::Request object
72
44
  #
73
45
  # @raise an appropriate connection error if unable to make the request to Facebook
74
46
  #
75
47
  # @return [Koala::HTTPService::Response] a response object representing the results from Facebook
76
- def self.make_request(path, args, verb, options = {})
77
- # if the verb isn't get or post, send it as a post argument with a method param
78
- args.merge!({:method => verb}) && verb = "post" if verb != "get" && verb != "post"
79
-
80
- # turn all the keys to strings (Faraday has issues with symbols under 1.8.7) and resolve UploadableIOs
81
- params = args.inject({}) {|hash, kv| hash[kv.first.to_s] = kv.last.is_a?(UploadableIO) ? kv.last.to_upload_io : kv.last; hash}
82
-
83
- # figure out our options for this request
84
- request_options = {:params => (verb == "get" ? params : {})}.merge(http_options || {}).merge(options)
85
- request_options[:use_ssl] = true if args["access_token"] # require https if there's a token
86
- if request_options[:use_ssl]
87
- ssl = (request_options[:ssl] ||= {})
88
- ssl[:verify] = true unless ssl.has_key?(:verify)
89
- end
90
-
91
- # if an api_version is specified and the path does not already contain
92
- # one, prepend it to the path
93
- api_version = request_options[:api_version] || Koala.config.api_version
94
- if api_version && !path_contains_api_version?(path)
95
- begins_with_slash = path[0] == "/"
96
- divider = begins_with_slash ? "" : "/"
97
- path = "/#{api_version}#{divider}#{path}"
98
- end
99
-
48
+ def self.make_request(request)
100
49
  # set up our Faraday connection
101
- # we have to manually assign params to the URL or the
102
- conn = Faraday.new(server(request_options), faraday_options(request_options), &(faraday_middleware || DEFAULT_MIDDLEWARE))
50
+ conn = Faraday.new(request.server, faraday_options(request.options), &(faraday_middleware || DEFAULT_MIDDLEWARE))
103
51
 
104
- # remember, all non-GET requests are turned into POSTs -- see the the start of this method
105
- if verb == "post" && options[:format] == :json
52
+ if request.verb == "post" && request.json?
53
+ # JSON requires a bit more handling
54
+ # remember, all non-GET requests are turned into POSTs, so this covers everything but GETs
106
55
  response = conn.post do |req|
107
- req.path = path
56
+ req.path = request.path
108
57
  req.headers["Content-Type"] = "application/json"
109
- req.body = params.to_json
58
+ req.body = request.post_args.to_json
110
59
  req
111
60
  end
112
61
  else
113
- response = conn.send(verb, path, (verb == "post" ? params : {}))
62
+ response = conn.send(request.verb, request.path, request.post_args)
114
63
  end
115
64
 
116
65
  # Log URL information
117
- Koala::Utils.debug "#{verb.upcase}: #{path} params: #{params.inspect}"
66
+ Koala::Utils.debug "#{request.verb.upcase}: #{request.path} params: #{request.raw_args.inspect}"
118
67
  Koala::HTTPService::Response.new(response.status.to_i, response.body, response.headers)
119
68
  end
120
69
 
@@ -130,21 +79,14 @@ module Koala
130
79
  # @return the appropriately-encoded string
131
80
  def self.encode_params(param_hash)
132
81
  ((param_hash || {}).sort_by{|k, v| k.to_s}.collect do |key_and_value|
133
- key_and_value[1] = JSON.dump(key_and_value[1]) unless key_and_value[1].is_a? String
134
- "#{key_and_value[0].to_s}=#{CGI.escape key_and_value[1]}"
82
+ value = key_and_value[1]
83
+ unless value.is_a? String
84
+ value = value.to_json
85
+ end
86
+ "#{key_and_value[0].to_s}=#{CGI.escape value}"
135
87
  end).join("&")
136
88
  end
137
89
 
138
- # Determines whether a given path already contains an API version.
139
- #
140
- # @param path the URL path.
141
- #
142
- # @return true or false accordingly.
143
- def self.path_contains_api_version?(path)
144
- match = /^\/?(v\d+(?:\.\d+)?)\//.match(path)
145
- !!(match && match[1])
146
- end
147
-
148
90
  private
149
91
 
150
92
  def self.faraday_options(options)
data/lib/koala/oauth.rb CHANGED
@@ -12,10 +12,10 @@ module Koala
12
12
  # @param app_id [String, Integer] a Facebook application ID
13
13
  # @param app_secret a Facebook application secret
14
14
  # @param oauth_callback_url the URL in your app to which users authenticating with OAuth will be sent
15
- def initialize(app_id, app_secret, oauth_callback_url = nil)
16
- @app_id = app_id
17
- @app_secret = app_secret
18
- @oauth_callback_url = oauth_callback_url
15
+ def initialize(app_id = nil, app_secret = nil, oauth_callback_url = nil)
16
+ @app_id = app_id || Koala.config.app_id
17
+ @app_secret = app_secret || Koala.config.app_secret
18
+ @oauth_callback_url = oauth_callback_url || Koala.config.oauth_callback_url
19
19
  end
20
20
 
21
21
  # Parses the cookie set Facebook's JavaScript SDK.
@@ -134,7 +134,7 @@ module Koala
134
134
  if response == ''
135
135
  raise BadFacebookResponse.new(200, '', 'generate_client_code received an error: empty response body')
136
136
  else
137
- result = JSON.load(response)
137
+ result = JSON.parse(response)
138
138
  end
139
139
 
140
140
  result.has_key?('code') ? result['code'] : raise(Koala::KoalaError.new("Facebook returned a valid response without the expected 'code' in the body (response = #{response})"))
@@ -240,7 +240,7 @@ module Koala
240
240
  raise OAuthSignatureError, 'Invalid (incomplete) signature data' unless encoded_sig && encoded_envelope
241
241
 
242
242
  signature = base64_url_decode(encoded_sig).unpack("H*").first
243
- envelope = JSON.load(base64_url_decode(encoded_envelope))
243
+ envelope = JSON.parse(base64_url_decode(encoded_envelope))
244
244
 
245
245
  raise OAuthSignatureError, "Unsupported algorithm #{envelope['algorithm']}" if envelope['algorithm'] != 'HMAC-SHA256'
246
246
 
@@ -260,7 +260,7 @@ module Koala
260
260
  end
261
261
 
262
262
  def parse_access_token(response_text)
263
- JSON.load(response_text)
263
+ JSON.parse(response_text)
264
264
  rescue JSON::ParserError
265
265
  response_text.split("&").inject({}) do |hash, bit|
266
266
  key, value = bit.split("=")
@@ -7,9 +7,6 @@ module Koala
7
7
  # @note: to subscribe to real-time updates, you must have an application access token
8
8
  # or provide the app secret when initializing your RealtimeUpdates object.
9
9
 
10
- # The application API interface used to communicate with Facebook.
11
- # @return [Koala::Facebook::API]
12
- attr_reader :api
13
10
  attr_reader :app_id, :app_access_token, :secret
14
11
 
15
12
  # Create a new RealtimeUpdates instance.
@@ -23,20 +20,27 @@ module Koala
23
20
  #
24
21
  # @raise ArgumentError if the application ID and one of the app access token or the secret are not provided.
25
22
  def initialize(options = {})
26
- @app_id = options[:app_id]
27
- @app_access_token = options[:app_access_token]
28
- @secret = options[:secret]
23
+ @app_id = options[:app_id] || Koala.config.app_id
24
+ @app_access_token = options[:app_access_token] || Koala.config.app_access_token
25
+ @secret = options[:secret] || Koala.config.app_secret
29
26
  unless @app_id && (@app_access_token || @secret) # make sure we have what we need
30
27
  raise ArgumentError, "Initialize must receive a hash with :app_id and either :app_access_token or :secret! (received #{options.inspect})"
31
28
  end
29
+ end
32
30
 
33
- # fetch the access token if we're provided a secret
34
- if @secret && !@app_access_token
35
- oauth = Koala::Facebook::OAuth.new(@app_id, @secret)
36
- @app_access_token = oauth.get_app_access_token
37
- end
31
+ # The app access token, either provided on initialization or fetched from Facebook using the
32
+ # app_id and secret.
33
+ def app_access_token
34
+ # If a token isn't provided but we need it, fetch it
35
+ @app_access_token ||= Koala::Facebook::OAuth.new(@app_id, @secret).get_app_access_token
36
+ end
38
37
 
39
- @api = API.new(@app_access_token)
38
+ # The application API interface used to communicate with Facebook.
39
+ # @return [Koala::Facebook::API]
40
+ def api
41
+ # Only instantiate the API if needed. validate_update doesn't require it, so we shouldn't
42
+ # make an unnecessary request to get the app_access_token.
43
+ @api ||= API.new(app_access_token)
40
44
  end
41
45
 
42
46
  # Subscribe to realtime updates for certain fields on a given object (user, page, etc.).
@@ -60,7 +64,7 @@ module Koala
60
64
  :callback_url => callback_url,
61
65
  }.merge(verify_token ? {:verify_token => verify_token} : {})
62
66
  # a subscription is a success if Facebook returns a 200 (after hitting your server for verification)
63
- @api.graph_call(subscription_path, args, 'post', options)
67
+ api.graph_call(subscription_path, args, 'post', options)
64
68
  end
65
69
 
66
70
  # Unsubscribe from updates for a particular object or from updates.
@@ -71,7 +75,7 @@ module Koala
71
75
  #
72
76
  # @raise A subclass of Koala::Facebook::APIError if the subscription request failed.
73
77
  def unsubscribe(object = nil, options = {})
74
- @api.graph_call(subscription_path, object ? {:object => object} : {}, "delete", options)
78
+ api.graph_call(subscription_path, object ? {:object => object} : {}, "delete", options)
75
79
  end
76
80
 
77
81
  # List all active subscriptions for this application.
@@ -80,7 +84,7 @@ module Koala
80
84
  #
81
85
  # @return [Array] a list of active subscriptions
82
86
  def list_subscriptions(options = {})
83
- @api.graph_call(subscription_path, {}, "get", options)
87
+ api.graph_call(subscription_path, {}, "get", options)
84
88
  end
85
89
 
86
90
  # As a security measure (to prevent DDoS attacks), Facebook sends a verification request to your server
@@ -129,12 +133,13 @@ module Koala
129
133
  raise AppSecretNotDefinedError, "You must init RealtimeUpdates with your app secret in order to validate updates"
130
134
  end
131
135
 
132
- if request_signature = headers['X-Hub-Signature'] || headers['HTTP_X_HUB_SIGNATURE'] and
133
- signature_parts = request_signature.split("sha1=")
134
- request_signature = signature_parts[1]
135
- calculated_signature = OpenSSL::HMAC.hexdigest('sha1', @secret, body)
136
- calculated_signature == request_signature
137
- end
136
+ request_signature = headers['X-Hub-Signature'] || headers['HTTP_X_HUB_SIGNATURE']
137
+ return unless request_signature
138
+
139
+ signature_parts = request_signature.split("sha1=")
140
+ request_signature = signature_parts[1]
141
+ calculated_signature = OpenSSL::HMAC.hexdigest('sha1', @secret, body)
142
+ calculated_signature == request_signature
138
143
  end
139
144
 
140
145
  # The Facebook subscription management URL for your application.
@@ -14,7 +14,6 @@ module Koala
14
14
  #
15
15
  # See http://developers.facebook.com/docs/test_users/.
16
16
  class TestUsers
17
-
18
17
  # The application API interface used to communicate with Facebook.
19
18
  # @return [Koala::Facebook::API]
20
19
  attr_reader :api
@@ -31,9 +30,10 @@ module Koala
31
30
  #
32
31
  # @raise ArgumentError if the application ID and one of the app access token or the secret are not provided.
33
32
  def initialize(options = {})
34
- @app_id = options[:app_id]
35
- @app_access_token = options[:app_access_token]
36
- @secret = options[:secret]
33
+ @app_id = options[:app_id] || Koala.config.app_id
34
+ @app_access_token = options[:app_access_token] || Koala.config.app_access_token
35
+ @secret = options[:secret] || Koala.config.app_secret
36
+
37
37
  unless @app_id && (@app_access_token || @secret) # make sure we have what we need
38
38
  raise ArgumentError, "Initialize must receive a hash with :app_id and either :app_access_token or :secret! (received #{options.inspect})"
39
39
  end
@@ -146,11 +146,12 @@ module Koala
146
146
  raise ArgumentError, "TestUsers#befriend requires hash arguments for both users with id and access_token"
147
147
  end
148
148
 
149
- u1_graph_api = API.new(user1_token)
150
- u2_graph_api = API.new(user2_token)
149
+ u1_graph_api = API.new(user1_token, secret)
150
+ u2_graph_api = API.new(user2_token, secret)
151
151
 
152
- u1_graph_api.graph_call("#{user1_id}/friends/#{user2_id}", {}, "post", options) &&
153
- u2_graph_api.graph_call("#{user2_id}/friends/#{user1_id}", {}, "post", options)
152
+ # if we have a secret token, flag that we want the appsecret_proof to be generated
153
+ u1_graph_api.graph_call("#{user1_id}/friends/#{user2_id}", {}, "post", options.merge(appsecret_proof: !!secret)) &&
154
+ u2_graph_api.graph_call("#{user2_id}/friends/#{user1_id}", {}, "post", options.merge(appsecret_proof: !!secret))
154
155
  end
155
156
 
156
157
  # Create a network of test users, all of whom are friends and have the same permissions.
data/lib/koala/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Koala
2
- VERSION = "2.5.0"
2
+ VERSION = "3.0.0"
3
3
  end
data/lib/koala.rb CHANGED
@@ -5,6 +5,7 @@ require 'json'
5
5
  # include koala modules
6
6
  require 'koala/errors'
7
7
  require 'koala/api'
8
+ require 'koala/api/graph_batch_api'
8
9
  require 'koala/oauth'
9
10
  require 'koala/realtime_updates'
10
11
  require 'koala/test_users'
@@ -13,6 +14,7 @@ require 'koala/test_users'
13
14
  require 'koala/http_service'
14
15
 
15
16
  # miscellaneous
17
+ require 'koala/configuration'
16
18
  require 'koala/utils'
17
19
  require 'koala/version'
18
20
  require 'ostruct'
@@ -36,14 +38,10 @@ module Koala
36
38
  end
37
39
 
38
40
  # Allows you to control various Koala configuration options.
39
- # Notable options:
40
- # * server endpoints: you can override any or all the server endpoints
41
- # (see HTTPService::DEFAULT_SERVERS) if you want to run requests through
42
- # other servers.
43
- # * api_version: controls which Facebook API version to use (v1.0, v2.0,
44
- # etc)
41
+ # NOTE: this is not currently threadsafe.
42
+ # See Koala::Configuration.
45
43
  def config
46
- @config ||= OpenStruct.new(HTTPService::DEFAULT_SERVERS)
44
+ @config ||= Configuration.new
47
45
  end
48
46
 
49
47
  # Used for testing.
@@ -61,7 +59,7 @@ module Koala
61
59
 
62
60
  # An convenenient alias to Koala.http_service.make_request.
63
61
  def self.make_request(path, args, verb, options = {})
64
- http_service.make_request(path, args, verb, options)
62
+ http_service.make_request(HTTPService::Request.new(path: path, args: args, verb: verb, options: options))
65
63
  end
66
64
 
67
65
  # we use Faraday as our main service, with mock as the other main one
data/readme.md CHANGED
@@ -1,10 +1,10 @@
1
1
  Koala [![Version](https://img.shields.io/gem/v/koala.svg)](https://rubygems.org/gems/koala) [![Dependencies](https://img.shields.io/gemnasium/arsduo/koala.svg)](https://gemnasium.com/arsduo/koala) [![Build Status](https://img.shields.io/travis/arsduo/koala.svg)](http://travis-ci.org/arsduo/koala) [![Code Climate](https://img.shields.io/codeclimate/github/arsduo/koala.svg)](https://codeclimate.com/github/arsduo/koala) [![Code Coverage](https://img.shields.io/codeclimate/coverage/github/arsduo/koala.svg)](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 REST API, realtime updates, test users, and OAuth validation. We wrote Koala with four goals:
3
+ [Koala](http://github.com/arsduo/koala) is a Facebook library for Ruby, supporting the Graph API (including the batch requests and photo uploads), realtime updates, test users, and OAuth validation. We wrote Koala with four goals:
4
4
 
5
5
  * Lightweight: Koala should be as light and simple as Facebook’s own libraries, providing API accessors and returning simple JSON.
6
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 JRuby, Rubinius, and REE as well as vanilla Ruby (1.8.7, 1.9.2, 1.9.3, and 2.0.0), and use the Faraday library to provide complete flexibility over how HTTP requests are made.
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
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!
@@ -12,9 +12,12 @@ Koala [![Version](https://img.shields.io/gem/v/koala.svg)](https://rubygems.org/
12
12
  Installation
13
13
  ------------
14
14
 
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.
17
+
15
18
  In Bundler:
16
19
  ```ruby
17
- gem "koala", "~> 2.2"
20
+ gem "koala"
18
21
  ```
19
22
 
20
23
  Otherwise:
@@ -22,25 +25,41 @@ Otherwise:
22
25
  [sudo|rvm] gem install koala
23
26
  ```
24
27
 
25
- Upgrading to 2.0+
26
- -----------------
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
+ ```
27
45
 
28
- Koala 2.0 is not a major refactor, but rather a set of small, mostly internal
29
- refactors, which should not require significant changes by users. See changelog.md for more
30
- details.
46
+ **Note**: this is not currently threadsafe. (PRs welcome as long as they support both threaded and
47
+ non-threaded configuration.)
31
48
 
32
49
  Graph API
33
50
  ---------
34
51
 
35
- The Graph API is the simple, slick new interface to Facebook's data.
36
- Using it with Koala is quite straightforward. First, you'll need an access token, which you can get through
37
- Facebook's [Graph API Explorer](https://developers.facebook.com/tools/explorer) (click on 'Get Access Token').
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
+
38
56
  Then, go exploring:
39
57
 
40
58
  ```ruby
41
59
  require 'koala'
42
-
43
- @graph = Koala::Facebook::API.new(oauth_access_token)
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)
44
63
 
45
64
  profile = @graph.get_object("me")
46
65
  friends = @graph.get_connections("me", "friends")
@@ -56,14 +75,14 @@ friends = @graph.get_connections("me", "friends")
56
75
  # For extra security (recommended), you can provide an appsecret parameter,
57
76
  # tying your access tokens to your app secret.
58
77
  # (See https://developers.facebook.com/docs/reference/api/securing-graph-api/
59
- # You'll need to turn on 'Require proof on all calls' in the advanced section
78
+
79
+ # You may need to turn on 'Require proof on all calls' in the advanced section
60
80
  # of your app's settings when doing this.
61
- @graph = Koala::Facebook::API.new(oauth_access_token, app_secret)
81
+ @graph = Koala::Facebook::API.new(access_token, app_secret)
62
82
 
63
83
  # Facebook is now versioning their API. # If you don't specify a version, Facebook
64
- # will default to the oldest version your app is allowed to use. Note that apps
65
- # created after f8 2014 *cannot* use the v1.0 API. See
66
- # https://developers.facebook.com/docs/apps/versions for more information.
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.
67
86
  #
68
87
  # You can specify version either globally:
69
88
  Koala.config.api_version = "v2.0"
@@ -115,85 +134,20 @@ the results apart from a long list of array entries:
115
134
 
116
135
  Check out the wiki for more details and examples.
117
136
 
118
- The REST API
119
- ------------
120
-
121
- Where the Graph API and the old REST API overlap, you should choose the Graph API. Unfortunately, that overlap is far from complete, and there are many important API calls that can't yet be done via the Graph.
122
-
123
- Fortunately, Koala supports the REST API using the very same interface; to use this, instantiate an API:
124
- ```ruby
125
- @rest = Koala::Facebook::API.new(oauth_access_token)
126
-
127
- @rest.fql_query(my_fql_query) # convenience method
128
- @rest.fql_multiquery(fql_query_hash) # convenience method
129
- @rest.rest_call("stream.publish", arguments_hash) # generic version
130
- ```
131
-
132
- Of course, you can use the Graph API methods on the same object -- the power of two APIs right in the palm of your hand.
133
- ```ruby
134
- @api = Koala::Facebook::API.new(oauth_access_token)
135
- fql = @api.fql_query(my_fql_query)
136
- @api.put_wall_post(process_result(fql))
137
- ```
138
-
139
- Configuration
140
- -------------
141
-
142
- You can change the host that koala makes requests to (point to a mock server, apigee, runscope etc..)
143
- ```ruby
144
- # config/initializers/koala.rb
145
- require 'koala'
146
-
147
- Koala.configure do |config|
148
- config.graph_server = 'my-graph-mock.mysite.com'
149
- # other common options are `rest_server` and `dialog_host`
150
- # see lib/koala/http_service.rb
151
- end
152
- ```
153
-
154
- Of course the defaults are the facebook endpoints and you can additionally configure the beta
155
- tier and video upload matching and replacement strings.
156
-
157
- OAuth
137
+ App Access Tokens
158
138
  -----
159
139
 
160
- You can use the Graph and REST APIs without an OAuth access token, but the real magic happens when you provide Facebook an OAuth token to prove you're authenticated. Koala provides an OAuth class to make that process easy:
140
+ You get your application's own access token, which can be used without a user session for subscriptions and certain other requests:
161
141
  ```ruby
162
142
  @oauth = Koala::Facebook::OAuth.new(app_id, app_secret, callback_url)
163
- ```
164
-
165
- If your application uses Koala and the Facebook [JavaScript SDK](http://github.com/facebook/facebook-js-sdk) (formerly Facebook Connect), you can use the OAuth class to parse the cookies:
166
- ```ruby
167
- # parses and returns a hash including the token and the user id
168
- # NOTE: this method can only be called once per session, as the OAuth code
169
- # Facebook supplies can only be redeemed once. Your application must handle
170
- # cross-request storage of this information; you can no longer call this method
171
- # multiple times.
172
- @oauth.get_user_info_from_cookies(cookies)
173
- ```
174
- And if you have to use the more complicated [redirect-based OAuth process](http://developers.facebook.com/docs/authentication/), Koala helps out there, too:
175
-
176
- ```ruby
177
- # generate authenticating URL
178
- @oauth.url_for_oauth_code
179
- # fetch the access token once you have the code
180
- @oauth.get_access_token(code)
181
- ```
182
-
183
- You can also get your application's own access token, which can be used without a user session for subscriptions and certain other requests:
184
- ```ruby
185
143
  @oauth.get_app_access_token
186
144
  ```
187
145
  For those building apps on Facebook, parsing signed requests is simple:
188
146
  ```ruby
189
147
  @oauth.parse_signed_request(signed_request_string)
190
148
  ```
191
- Or, if for some horrible reason, you're still using session keys, despair not! It's easy to turn them into shiny, modern OAuth tokens:
192
- ```ruby
193
- @oauth.get_token_from_session_key(session_key)
194
- @oauth.get_tokens_from_session_keys(array_of_session_keys)
195
- ```
196
- That's it! It's pretty simple once you get the hang of it. If you're new to OAuth, though, check out the wiki and the OAuth Playground example site (see below).
149
+
150
+ The OAuth class has additional methods that may occasionally be useful.
197
151
 
198
152
  Real-time Updates
199
153
  -----------------
@@ -202,6 +156,7 @@ Sometimes, reaching out to Facebook is a pain -- let it reach out to you instead
202
156
 
203
157
  Koala makes it easy to interact with your applications using the RealtimeUpdates class:
204
158
  ```ruby
159
+ # This class also supports the defaults as described above
205
160
  @updates = Koala::Facebook::RealtimeUpdates.new(app_id: app_id, secret: secret)
206
161
  ```
207
162
  You can do just about anything with your real-time update subscriptions using the RealtimeUpdates class:
@@ -225,14 +180,16 @@ For more information about meet_challenge and the RealtimeUpdates class, check o
225
180
  Test Users
226
181
  ----------
227
182
 
228
- We also support the test users API, allowing you to conjure up fake users and command them to do your bidding using the Graph or REST API:
183
+ 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:
229
184
  ```ruby
185
+ # This class also supports the defaults as described above
230
186
  @test_users = Koala::Facebook::TestUsers.new(app_id: id, secret: secret)
231
187
  user = @test_users.create(is_app_installed, desired_permissions)
232
188
  user_graph_api = Koala::Facebook::API.new(user["access_token"])
233
189
  # or, if you want to make a whole community:
234
190
  @test_users.create_network(network_size, is_app_installed, common_permissions)
235
191
  ```
192
+
236
193
  Talking to Facebook
237
194
  -------------------
238
195
 
@@ -255,14 +212,6 @@ Some resources to help you as you play with Koala and the Graph API:
255
212
  * Complete Koala documentation <a href="https://github.com/arsduo/koala/wiki">on the wiki</a>
256
213
  * 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.
257
214
  * 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
258
- * The Koala-powered <a href="http://oauth.twoalex.com" target="_blank">OAuth Playground</a>, where you can easily generate OAuth access tokens and any other data needed to test out the APIs or OAuth
259
- * Follow Koala on <a href="http://www.facebook.com/pages/Koala/315368291823667">Facebook</a> and <a href="https://twitter.com/#!/koala_fb">Twitter</a> for SDK updates and occasional news about Facebook API changes.
260
-
261
- *Note*: I use the Koala issues tracker on Github to triage and address issues
262
- with the gem itself; if you need help using the Facebook API, the above
263
- resources will be far more effective. Depending on how much time I have, Github
264
- issues filed about how to use the Facebook API may be closed with a reference
265
- to the Facebook Stack Overflow page.
266
215
 
267
216
  Testing
268
217
  -------
@@ -280,26 +229,18 @@ LIVE=true bundle exec rake spec
280
229
  # you can also test against Facebook's beta tier
281
230
  LIVE=true BETA=true bundle exec rake spec
282
231
  ```
232
+
283
233
  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.
284
234
 
285
235
  Maintenance
286
236
  -----------
287
237
 
288
238
  _Pull requests_: Koala exists as it does thanks to the amazing support and work of community members of all
289
- backgrounds and levels of experience. Pull requests are very welcome! If you have any questions,
290
- just open an issue.
239
+ backgrounds and levels of experience. Pull requests are very welcome!
240
+
241
+ _Issues_: If you have any questions about the gem, found an issue in the Ruby code or
242
+ documentation, or have another question that isn't right for StackOverflow, just open an issue and fill out the template.
291
243
 
292
244
  Please note that this project is released with a Contributor Code of Conduct. By participating in
293
245
  this project you agree to abide by its terms. See
294
246
  [code_of_conduct.md](https://github.com/arsduo/koala/blob/master/code_of_conduct.md) for more information.
295
-
296
- _Schedule_: In order to keep Koala moving forward on a regular and predictable schedule, I will
297
- address issues and pull requests at least three times a year: late July/early August, late
298
- December/early January, and late March/early April. I may respond to issues in between maintenance
299
- periods, but it'll depend on other life/work goings-on.
300
-
301
- Breaking/new Facebook changes and other urgent issues obviously will get addressed much more
302
- quickly. (We've never had a security issue, but obviously that would be priority 0.)
303
-
304
- Have questions? Found a breaking bug or urgent issue? [Tweet at me](http://twitter.com/arsduo) --
305
- I'm always happy to respond.