google-api-client 0.1.3 → 0.2.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.
- data/CHANGELOG +8 -0
- data/README +1 -1
- data/bin/google-api +174 -120
- data/lib/google/api_client.rb +333 -135
- data/lib/google/api_client/discovery.rb +106 -108
- data/lib/google/api_client/environment.rb +13 -0
- data/lib/google/api_client/errors.rb +30 -0
- data/lib/google/api_client/parsers/json_parser.rb +1 -0
- data/lib/google/api_client/version.rb +3 -2
- data/lib/google/inflection.rb +23 -0
- data/spec/google/api_client/discovery_spec.rb +381 -381
- data/spec/google/api_client_spec.rb +78 -28
- data/tasks/gem.rake +4 -6
- metadata +32 -60
data/CHANGELOG
CHANGED
@@ -1,3 +1,11 @@
|
|
1
|
+
== 0.2.0
|
2
|
+
|
3
|
+
* updated to use v1 of the discovery API
|
4
|
+
* updated to use httpadapter 1.0.0
|
5
|
+
* added OAuth 2 support to the command line tool
|
6
|
+
* renamed some switches in the command line tool
|
7
|
+
* added additional configuration capabilities
|
8
|
+
|
1
9
|
== 0.1.3
|
2
10
|
|
3
11
|
* added support for manual overrides of the discovery URI
|
data/README
CHANGED
@@ -44,7 +44,7 @@ APIs.
|
|
44
44
|
client.authorization.fetch_token_credential!(:verifier => '12345')
|
45
45
|
|
46
46
|
# Discover available methods
|
47
|
-
method_names = client.
|
47
|
+
method_names = client.discovered_api('buzz').to_h.keys
|
48
48
|
|
49
49
|
# Make an API call
|
50
50
|
response = client.execute(
|
data/bin/google-api
CHANGED
@@ -26,7 +26,8 @@ module Google
|
|
26
26
|
|
27
27
|
def do_GET(request, response)
|
28
28
|
$verifier ||= Addressable::URI.unencode_component(
|
29
|
-
request.request_uri.to_s[/\?.*oauth_verifier=([^&$]+)(&|$)/, 1]
|
29
|
+
request.request_uri.to_s[/\?.*oauth_verifier=([^&$]+)(&|$)/, 1] ||
|
30
|
+
request.request_uri.to_s[/\?.*code=([^&$]+)(&|$)/, 1]
|
30
31
|
)
|
31
32
|
response.status = WEBrick::HTTPStatus::RC_ACCEPTED
|
32
33
|
# This javascript will auto-close the tab after the
|
@@ -92,24 +93,24 @@ HTML
|
|
92
93
|
options[:scope] = s
|
93
94
|
end
|
94
95
|
opts.on(
|
95
|
-
"--client-
|
96
|
-
"Set the
|
96
|
+
"--client-id <key>", String,
|
97
|
+
"Set the OAuth client id or key") do |k|
|
97
98
|
options[:client_credential_key] = k
|
98
99
|
end
|
99
100
|
opts.on(
|
100
101
|
"--client-secret <secret>", String,
|
101
|
-
"Set the
|
102
|
+
"Set the OAuth client secret") do |s|
|
102
103
|
options[:client_credential_secret] = s
|
103
104
|
end
|
104
105
|
opts.on(
|
105
|
-
"
|
106
|
-
"Perform discovery on
|
107
|
-
options[:
|
106
|
+
"--api <name>", String,
|
107
|
+
"Perform discovery on API") do |s|
|
108
|
+
options[:api] = s
|
108
109
|
end
|
109
110
|
opts.on(
|
110
111
|
"--service-version <id>", String,
|
111
112
|
"Select service version") do |id|
|
112
|
-
options[:
|
113
|
+
options[:version] = id
|
113
114
|
end
|
114
115
|
opts.on(
|
115
116
|
"--content-type <format>", String,
|
@@ -162,10 +163,11 @@ HTML
|
|
162
163
|
|
163
164
|
opts.separator(
|
164
165
|
"\nAvailable commands:\n" +
|
165
|
-
" oauth-login Log a user into an API\n" +
|
166
|
-
"
|
167
|
-
"
|
168
|
-
"
|
166
|
+
" oauth-1-login Log a user into an API with OAuth 1.0a\n" +
|
167
|
+
" oauth-2-login Log a user into an API with OAuth 2.0 d10\n" +
|
168
|
+
" list List the methods available for a service\n" +
|
169
|
+
" execute Execute a method on the API\n" +
|
170
|
+
" irb Start an interactive client session"
|
169
171
|
)
|
170
172
|
end
|
171
173
|
end
|
@@ -180,23 +182,98 @@ HTML
|
|
180
182
|
self.send(symbol)
|
181
183
|
end
|
182
184
|
|
185
|
+
def client
|
186
|
+
require 'signet/oauth_1/client'
|
187
|
+
require 'yaml'
|
188
|
+
require 'irb'
|
189
|
+
config_file = File.expand_path('~/.google-api.yaml')
|
190
|
+
authorization = nil
|
191
|
+
if File.exist?(config_file)
|
192
|
+
config = open(config_file, 'r') { |file| YAML.load(file.read) }
|
193
|
+
else
|
194
|
+
config = {}
|
195
|
+
end
|
196
|
+
if config["mechanism"]
|
197
|
+
authorization = config["mechanism"].to_sym
|
198
|
+
end
|
199
|
+
|
200
|
+
client = Google::APIClient.new(:authorization => authorization)
|
201
|
+
|
202
|
+
case authorization
|
203
|
+
when :oauth_1
|
204
|
+
if client.authorization &&
|
205
|
+
!client.authorization.kind_of?(Signet::OAuth1::Client)
|
206
|
+
STDERR.puts(
|
207
|
+
"Unexpected authorization mechanism: " +
|
208
|
+
"#{client.authorization.class}"
|
209
|
+
)
|
210
|
+
exit(1)
|
211
|
+
end
|
212
|
+
config = open(config_file, 'r') { |file| YAML.load(file.read) }
|
213
|
+
client.authorization.client_credential_key =
|
214
|
+
config["client_credential_key"]
|
215
|
+
client.authorization.client_credential_secret =
|
216
|
+
config["client_credential_secret"]
|
217
|
+
client.authorization.token_credential_key =
|
218
|
+
config["token_credential_key"]
|
219
|
+
client.authorization.token_credential_secret =
|
220
|
+
config["token_credential_secret"]
|
221
|
+
when :oauth_2
|
222
|
+
if client.authorization &&
|
223
|
+
!client.authorization.kind_of?(Signet::OAuth2::Client)
|
224
|
+
STDERR.puts(
|
225
|
+
"Unexpected authorization mechanism: " +
|
226
|
+
"#{client.authorization.class}"
|
227
|
+
)
|
228
|
+
exit(1)
|
229
|
+
end
|
230
|
+
config = open(config_file, 'r') { |file| YAML.load(file.read) }
|
231
|
+
client.authorization.scope = options[:scope]
|
232
|
+
client.authorization.client_id = config["client_id"]
|
233
|
+
client.authorization.client_secret = config["client_secret"]
|
234
|
+
client.authorization.access_token = config["access_token"]
|
235
|
+
client.authorization.refresh_token = config["refresh_token"]
|
236
|
+
else
|
237
|
+
# Dunno?
|
238
|
+
end
|
239
|
+
|
240
|
+
if options[:discovery_uri]
|
241
|
+
client.discovery_uri = options[:discovery_uri]
|
242
|
+
end
|
243
|
+
|
244
|
+
return client
|
245
|
+
end
|
246
|
+
|
247
|
+
def api_version(api, version)
|
248
|
+
v = version
|
249
|
+
if !version
|
250
|
+
if client.preferred_version(api)
|
251
|
+
v = client.preferred_version(api).version
|
252
|
+
else
|
253
|
+
v = 'v1'
|
254
|
+
end
|
255
|
+
end
|
256
|
+
return v
|
257
|
+
end
|
258
|
+
|
183
259
|
COMMANDS = [
|
184
|
-
:
|
260
|
+
:oauth_1_login,
|
261
|
+
:oauth_2_login,
|
185
262
|
:list,
|
186
263
|
:execute,
|
187
264
|
:irb,
|
188
265
|
:fuzz
|
189
266
|
]
|
190
267
|
|
191
|
-
def
|
268
|
+
def oauth_1_login
|
192
269
|
require 'signet/oauth_1/client'
|
193
270
|
require 'launchy'
|
194
271
|
require 'yaml'
|
195
272
|
if options[:client_credential_key] &&
|
196
273
|
options[:client_credential_secret]
|
197
|
-
scope = options[:scope]
|
198
274
|
config = {
|
199
|
-
"
|
275
|
+
"mechanism" => "oauth_1",
|
276
|
+
"scope" => options[:scope],
|
200
277
|
"client_credential_key" => options[:client_credential_key],
|
201
278
|
"client_credential_secret" => options[:client_credential_secret],
|
202
279
|
"token_credential_key" => nil,
|
@@ -229,19 +306,8 @@ HTML
|
|
229
306
|
:client_credential_secret => 'anonymous',
|
230
307
|
:callback => "http://localhost:#{OAUTH_SERVER_PORT}/"
|
231
308
|
)
|
232
|
-
scope = options[:scope]
|
233
|
-
# Special cases
|
234
|
-
case scope
|
235
|
-
when "https://www.googleapis.com/auth/buzz",
|
236
|
-
"https://www.googleapis.com/auth/buzz.readonly"
|
237
|
-
oauth_client.authorization_uri =
|
238
|
-
'https://www.google.com/buzz/api/auth/OAuthAuthorizeToken?' +
|
239
|
-
"domain=#{oauth_client.client_credential_key}&" +
|
240
|
-
"scope=#{scope}&" +
|
241
|
-
"xoauth_displayname=Google%20API%20Client"
|
242
|
-
end
|
243
309
|
oauth_client.fetch_temporary_credential!(:additional_parameters => {
|
244
|
-
:scope => scope,
|
310
|
+
:scope => options[:scope],
|
245
311
|
:xoauth_displayname => 'Google API Client'
|
246
312
|
})
|
247
313
|
|
@@ -251,7 +317,7 @@ HTML
|
|
251
317
|
server.start
|
252
318
|
oauth_client.fetch_token_credential!(:verifier => $verifier)
|
253
319
|
config = {
|
254
|
-
"scope" => scope,
|
320
|
+
"scope" => options[:scope],
|
255
321
|
"client_credential_key" =>
|
256
322
|
oauth_client.client_credential_key,
|
257
323
|
"client_credential_secret" =>
|
@@ -267,34 +333,90 @@ HTML
|
|
267
333
|
end
|
268
334
|
end
|
269
335
|
|
336
|
+
def oauth_2_login
|
337
|
+
require 'signet/oauth_2/client'
|
338
|
+
require 'launchy'
|
339
|
+
require 'yaml'
|
340
|
+
if !options[:client_credential_key] ||
|
341
|
+
!options[:client_credential_secret]
|
342
|
+
STDERR.puts('No client ID and secret supplied.')
|
343
|
+
exit(1)
|
344
|
+
end
|
345
|
+
if options[:access_token]
|
346
|
+
config = {
|
347
|
+
"mechanism" => "oauth_2",
|
348
|
+
"scope" => options[:scope],
|
349
|
+
"client_id" => options[:client_credential_key],
|
350
|
+
"client_secret" => options[:client_credential_secret],
|
351
|
+
"access_token" => options[:access_token],
|
352
|
+
"refresh_token" => options[:refresh_token]
|
353
|
+
}
|
354
|
+
config_file = File.expand_path('~/.google-api.yaml')
|
355
|
+
open(config_file, 'w') { |file| file.write(YAML.dump(config)) }
|
356
|
+
exit(0)
|
357
|
+
else
|
358
|
+
$verifier = nil
|
359
|
+
# TODO(bobaman): Cross-platform?
|
360
|
+
logger = WEBrick::Log.new('/dev/null')
|
361
|
+
server = WEBrick::HTTPServer.new(
|
362
|
+
:Port => OAUTH_SERVER_PORT,
|
363
|
+
:Logger => logger,
|
364
|
+
:AccessLog => logger
|
365
|
+
)
|
366
|
+
trap("INT") { server.shutdown }
|
367
|
+
|
368
|
+
server.mount("/", OAuthVerifierServlet)
|
369
|
+
|
370
|
+
oauth_client = Signet::OAuth2::Client.new(
|
371
|
+
:authorization_uri =>
|
372
|
+
'https://www.google.com/accounts/o8/oauth2/authorization',
|
373
|
+
:token_credential_uri =>
|
374
|
+
'https://www.google.com/accounts/o8/oauth2/token',
|
375
|
+
:client_id => options[:client_credential_key],
|
376
|
+
:client_secret => options[:client_credential_secret],
|
377
|
+
:redirect_uri => "http://localhost:#{OAUTH_SERVER_PORT}/",
|
378
|
+
:scope => options[:scope]
|
379
|
+
)
|
380
|
+
|
381
|
+
# Launch browser
|
382
|
+
Launchy::Browser.run(oauth_client.authorization_uri.to_s)
|
383
|
+
|
384
|
+
server.start
|
385
|
+
oauth_client.code = $verifier
|
386
|
+
oauth_client.fetch_access_token!
|
387
|
+
config = {
|
388
|
+
"mechanism" => "oauth_2",
|
389
|
+
"scope" => options[:scope],
|
390
|
+
"client_id" => oauth_client.client_id,
|
391
|
+
"client_secret" => oauth_client.client_secret,
|
392
|
+
"access_token" => oauth_client.access_token,
|
393
|
+
"refresh_token" => oauth_client.refresh_token
|
394
|
+
}
|
395
|
+
config_file = File.expand_path('~/.google-api.yaml')
|
396
|
+
open(config_file, 'w') { |file| file.write(YAML.dump(config)) }
|
397
|
+
exit(0)
|
398
|
+
end
|
399
|
+
end
|
400
|
+
|
270
401
|
def list
|
271
|
-
|
272
|
-
unless
|
273
|
-
STDERR.puts('No
|
402
|
+
api = options[:api]
|
403
|
+
unless api
|
404
|
+
STDERR.puts('No API name supplied.')
|
274
405
|
exit(1)
|
275
406
|
end
|
276
|
-
client = Google::APIClient.new(
|
277
|
-
:service => service_name,
|
278
|
-
:authorization => nil
|
279
|
-
)
|
407
|
+
client = Google::APIClient.new(:authorization => nil)
|
280
408
|
if options[:discovery_uri]
|
281
409
|
client.discovery_uri = options[:discovery_uri]
|
282
410
|
end
|
283
|
-
|
284
|
-
|
285
|
-
client.latest_service_version(service_name).version
|
286
|
-
service = client.discovered_service(service_name, service_version)
|
411
|
+
version = api_version(api, options[:version])
|
412
|
+
service = client.discovered_api(api, version)
|
287
413
|
rpcnames = service.to_h.keys
|
288
414
|
puts rpcnames.sort.join("\n")
|
289
415
|
exit(0)
|
290
416
|
end
|
291
417
|
|
292
418
|
def execute
|
293
|
-
|
294
|
-
require 'yaml'
|
295
|
-
config_file = File.expand_path('~/.google-api.yaml')
|
296
|
-
signed = File.exist?(config_file)
|
297
|
-
authorization_type = :oauth_1
|
419
|
+
client = self.client
|
298
420
|
|
299
421
|
# Setup HTTP request data
|
300
422
|
request_body = ''
|
@@ -308,28 +430,6 @@ HTML
|
|
308
430
|
headers << ['Content-Type', 'application/json']
|
309
431
|
end
|
310
432
|
|
311
|
-
configure_authorization = lambda do |client|
|
312
|
-
if !client.authorization.kind_of?(Signet::OAuth1::Client)
|
313
|
-
STDERR.puts(
|
314
|
-
"Unexpected authorization mechanism: " +
|
315
|
-
"#{client.authorization.class}"
|
316
|
-
)
|
317
|
-
exit(1)
|
318
|
-
end
|
319
|
-
config = open(config_file, 'r') { |file| YAML.load(file.read) }
|
320
|
-
client.authorization.client_credential_key =
|
321
|
-
config["client_credential_key"]
|
322
|
-
client.authorization.client_credential_secret =
|
323
|
-
config["client_credential_secret"]
|
324
|
-
client.authorization.token_credential_key =
|
325
|
-
config["token_credential_key"]
|
326
|
-
client.authorization.token_credential_secret =
|
327
|
-
config["token_credential_secret"]
|
328
|
-
if client.authorization.token_credential == nil
|
329
|
-
authorization_type = :two_legged_oauth_1
|
330
|
-
end
|
331
|
-
end
|
332
|
-
|
333
433
|
if options[:uri]
|
334
434
|
# Make request with URI manually specified
|
335
435
|
uri = Addressable::URI.parse(options[:uri])
|
@@ -345,13 +445,8 @@ HTML
|
|
345
445
|
method = options[:http_method]
|
346
446
|
method ||= request_body == '' ? 'GET' : 'POST'
|
347
447
|
method.upcase!
|
348
|
-
client = Google::APIClient.new(:authorization => authorization_type)
|
349
|
-
if options[:discovery_uri]
|
350
|
-
client.discovery_uri = options[:discovery_uri]
|
351
|
-
end
|
352
|
-
configure_authorization.call(client) if signed
|
353
448
|
request = [method, uri.to_str, headers, [request_body]]
|
354
|
-
request = client.
|
449
|
+
request = client.generate_authenticated_request(:request => request)
|
355
450
|
response = client.transmit_request(request)
|
356
451
|
status, headers, body = response
|
357
452
|
puts body
|
@@ -362,25 +457,14 @@ HTML
|
|
362
457
|
STDERR.puts('No rpcname supplied.')
|
363
458
|
exit(1)
|
364
459
|
end
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
:service => service_name,
|
369
|
-
:authorization => authorization_type
|
370
|
-
)
|
371
|
-
if options[:discovery_uri]
|
372
|
-
client.discovery_uri = options[:discovery_uri]
|
373
|
-
end
|
374
|
-
configure_authorization.call(client) if signed
|
375
|
-
service_version =
|
376
|
-
options[:service_version] ||
|
377
|
-
client.latest_service_version(service_name).version
|
378
|
-
service = client.discovered_service(service_name, service_version)
|
460
|
+
api = options[:api] || self.rpcname[/^([^\.]+)\./, 1]
|
461
|
+
version = api_version(api, options[:version])
|
462
|
+
service = client.discovered_api(api, version)
|
379
463
|
method = service.to_h[self.rpcname]
|
380
464
|
if !method
|
381
465
|
STDERR.puts(
|
382
466
|
"Method #{self.rpcname} does not exist for " +
|
383
|
-
"#{
|
467
|
+
"#{api}-#{version}."
|
384
468
|
)
|
385
469
|
exit(1)
|
386
470
|
end
|
@@ -394,7 +478,7 @@ HTML
|
|
394
478
|
end
|
395
479
|
begin
|
396
480
|
response = client.execute(
|
397
|
-
method, parameters, request_body, headers
|
481
|
+
method, parameters, request_body, headers
|
398
482
|
)
|
399
483
|
status, headers, body = response
|
400
484
|
puts body
|
@@ -407,37 +491,7 @@ HTML
|
|
407
491
|
end
|
408
492
|
|
409
493
|
def irb
|
410
|
-
|
411
|
-
require 'yaml'
|
412
|
-
require 'irb'
|
413
|
-
config_file = File.expand_path('~/.google-api.yaml')
|
414
|
-
signed = File.exist?(config_file)
|
415
|
-
|
416
|
-
$client = Google::APIClient.new(
|
417
|
-
:service => options[:service_name],
|
418
|
-
:authorization => (signed ? :oauth_1 : nil)
|
419
|
-
)
|
420
|
-
|
421
|
-
if signed
|
422
|
-
if $client.authorization &&
|
423
|
-
!$client.authorization.kind_of?(Signet::OAuth1::Client)
|
424
|
-
STDERR.puts(
|
425
|
-
"Unexpected authorization mechanism: " +
|
426
|
-
"#{$client.authorization.class}"
|
427
|
-
)
|
428
|
-
exit(1)
|
429
|
-
end
|
430
|
-
config = open(config_file, 'r') { |file| YAML.load(file.read) }
|
431
|
-
$client.authorization.client_credential_key =
|
432
|
-
config["client_credential_key"]
|
433
|
-
$client.authorization.client_credential_secret =
|
434
|
-
config["client_credential_secret"]
|
435
|
-
$client.authorization.token_credential_key =
|
436
|
-
config["token_credential_key"]
|
437
|
-
$client.authorization.token_credential_secret =
|
438
|
-
config["token_credential_secret"]
|
439
|
-
end
|
440
|
-
|
494
|
+
$client = self.client
|
441
495
|
# Otherwise IRB will misinterpret command-line options
|
442
496
|
ARGV.clear
|
443
497
|
IRB.start(__FILE__)
|
data/lib/google/api_client.rb
CHANGED
@@ -12,56 +12,132 @@
|
|
12
12
|
# See the License for the specific language governing permissions and
|
13
13
|
# limitations under the License.
|
14
14
|
|
15
|
+
|
15
16
|
require 'httpadapter'
|
16
17
|
require 'json'
|
17
18
|
require 'stringio'
|
18
19
|
|
20
|
+
require 'google/api_client/errors'
|
21
|
+
require 'google/api_client/environment'
|
19
22
|
require 'google/api_client/discovery'
|
20
23
|
|
21
24
|
module Google
|
22
25
|
# TODO(bobaman): Document all this stuff.
|
23
26
|
|
27
|
+
|
24
28
|
##
|
25
|
-
# This class manages communication
|
29
|
+
# This class manages APIs communication.
|
26
30
|
class APIClient
|
27
31
|
##
|
28
|
-
#
|
29
|
-
#
|
30
|
-
|
31
|
-
|
32
|
-
|
32
|
+
# Creates a new Google API client.
|
33
|
+
#
|
34
|
+
# @param [Hash] options The configuration parameters for the client.
|
35
|
+
# @option options [Symbol, #generate_authenticated_request] :authorization
|
36
|
+
# (:oauth_1)
|
37
|
+
# The authorization mechanism used by the client. The following
|
38
|
+
# mechanisms are supported out-of-the-box:
|
39
|
+
# <ul>
|
40
|
+
# <li><code>:two_legged_oauth_1</code></li>
|
41
|
+
# <li><code>:oauth_1</code></li>
|
42
|
+
# <li><code>:oauth_2</code></li>
|
43
|
+
# </ul>
|
44
|
+
# @option options [String] :host ("www.googleapis.com")
|
45
|
+
# The API hostname used by the client. This rarely needs to be changed.
|
46
|
+
# @option options [String] :application_name
|
47
|
+
# The name and version of the application using the client. This should
|
48
|
+
# be given in the form `"{name}/{version}"`.
|
49
|
+
# @option options [String] :user_agent
|
50
|
+
# ("{app_name} google-api-ruby-client/{version} {os_name}/{os_version}")
|
51
|
+
# The user agent used by the client. Most developers will want to
|
52
|
+
# leave this value alone and use the `:application_name` option instead.
|
33
53
|
def initialize(options={})
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
self.
|
54
|
+
# Normalize key to String to allow indifferent access.
|
55
|
+
options = options.inject({}) do |accu, (key, value)|
|
56
|
+
accu[key.to_s] = value
|
57
|
+
accu
|
58
|
+
end
|
59
|
+
# Almost all API usage will have a host of 'www.googleapis.com'.
|
60
|
+
self.host = options["host"] || 'www.googleapis.com'
|
61
|
+
# Most developers will want to leave this value alone and use the
|
62
|
+
# application_name option.
|
63
|
+
self.user_agent = options["user_agent"] || (
|
64
|
+
(options["application_name"] || '')
|
65
|
+
'google-api-ruby-client/' + VERSION::STRING +
|
66
|
+
' ' + ENV::OS_VERSION
|
67
|
+
).strip
|
68
|
+
# This is mostly a default for the sake of convenience.
|
69
|
+
# Unlike most other options, this one may be nil, so we check for
|
70
|
+
# the presence of the key rather than checking the value.
|
71
|
+
if options.has_key?("parser")
|
72
|
+
self.parser = options["parser"]
|
73
|
+
else
|
74
|
+
require 'google/api_client/parsers/json_parser'
|
75
|
+
# NOTE: Do not rely on this default value, as it may change
|
76
|
+
self.parser = Google::APIClient::JSONParser
|
77
|
+
end
|
78
|
+
# The writer method understands a few Symbols and will generate useful
|
79
|
+
# default authentication mechanisms.
|
80
|
+
self.authorization = options["authorization"] || :oauth_2
|
81
|
+
# The HTTP adapter controls all of the HTTP traffic the client generates.
|
82
|
+
# By default, Net::HTTP is used, but adding support for other clients
|
83
|
+
# is trivial.
|
84
|
+
if options["http_adapter"]
|
85
|
+
self.http_adapter = options["http_adapter"]
|
86
|
+
else
|
87
|
+
require 'httpadapter/adapters/net_http'
|
88
|
+
# NOTE: Do not rely on this default value, as it may change
|
89
|
+
self.http_adapter = HTTPAdapter::NetHTTPAdapter.new
|
90
|
+
end
|
91
|
+
@discovery_uris = {}
|
92
|
+
@discovery_documents = {}
|
93
|
+
@discovered_apis = {}
|
41
94
|
return self
|
42
95
|
end
|
43
96
|
|
97
|
+
|
44
98
|
##
|
45
99
|
# Returns the parser used by the client.
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
100
|
+
#
|
101
|
+
# @return [#serialize, #parse]
|
102
|
+
# The parser used by the client. Any object that implements both a
|
103
|
+
# <code>#serialize</code> and a <code>#parse</code> method may be used.
|
104
|
+
# If <code>nil</code>, no parsing will be done.
|
105
|
+
attr_reader :parser
|
106
|
+
|
107
|
+
##
|
108
|
+
# Sets the parser used by the client.
|
109
|
+
#
|
110
|
+
# @param [#serialize, #parse] new_parser
|
111
|
+
# The parser used by the client. Any object that implements both a
|
112
|
+
# <code>#serialize</code> and a <code>#parse</code> method may be used.
|
113
|
+
# If <code>nil</code>, no parsing will be done.
|
114
|
+
def parser=(new_parser)
|
115
|
+
if new_parser &&
|
116
|
+
!new_parser.respond_to?(:serialize) &&
|
117
|
+
!new_parser.respond_to?(:parse)
|
118
|
+
raise TypeError,
|
119
|
+
'Expected parser object to respond to #serialize and #parse.'
|
51
120
|
end
|
52
|
-
|
121
|
+
@parser = new_parser
|
53
122
|
end
|
54
123
|
|
55
124
|
##
|
56
125
|
# Returns the authorization mechanism used by the client.
|
57
126
|
#
|
58
127
|
# @return [#generate_authenticated_request] The authorization mechanism.
|
59
|
-
|
60
|
-
|
128
|
+
attr_reader :authorization
|
129
|
+
|
130
|
+
##
|
131
|
+
# Sets the authorization mechanism used by the client.
|
132
|
+
#
|
133
|
+
# @param [#generate_authenticated_request] new_authorization
|
134
|
+
# The new authorization mechanism.
|
135
|
+
def authorization=(new_authorization)
|
136
|
+
case new_authorization
|
61
137
|
when :oauth_1, :oauth
|
62
138
|
require 'signet/oauth_1/client'
|
63
139
|
# NOTE: Do not rely on this default value, as it may change
|
64
|
-
|
140
|
+
new_authorization = Signet::OAuth1::Client.new(
|
65
141
|
:temporary_credential_uri =>
|
66
142
|
'https://www.google.com/accounts/OAuthGetRequestToken',
|
67
143
|
:authorization_uri =>
|
@@ -74,79 +150,175 @@ module Google
|
|
74
150
|
when :two_legged_oauth_1, :two_legged_oauth
|
75
151
|
require 'signet/oauth_1/client'
|
76
152
|
# NOTE: Do not rely on this default value, as it may change
|
77
|
-
|
153
|
+
new_authorization = Signet::OAuth1::Client.new(
|
78
154
|
:client_credential_key => nil,
|
79
155
|
:client_credential_secret => nil,
|
80
156
|
:two_legged => true
|
81
157
|
)
|
158
|
+
when :oauth_2
|
159
|
+
require 'signet/oauth_2/client'
|
160
|
+
# NOTE: Do not rely on this default value, as it may change
|
161
|
+
new_authorization = Signet::OAuth2::Client.new(
|
162
|
+
:authorization_uri =>
|
163
|
+
'https://accounts.google.com/o/oauth2/auth',
|
164
|
+
:token_credential_uri =>
|
165
|
+
'https://accounts.google.com/o/oauth2/token'
|
166
|
+
)
|
82
167
|
when nil
|
83
168
|
# No authorization mechanism
|
84
169
|
else
|
85
|
-
if
|
86
|
-
:generate_authenticated_request)
|
170
|
+
if !new_authorization.respond_to?(:generate_authenticated_request)
|
87
171
|
raise TypeError,
|
88
172
|
'Expected authorization mechanism to respond to ' +
|
89
173
|
'#generate_authenticated_request.'
|
90
174
|
end
|
91
175
|
end
|
92
|
-
|
176
|
+
@authorization = new_authorization
|
177
|
+
return @authorization
|
93
178
|
end
|
94
179
|
|
95
180
|
##
|
96
|
-
#
|
181
|
+
# Returns the HTTP adapter used by the client.
|
97
182
|
#
|
98
|
-
# @
|
99
|
-
# The
|
100
|
-
|
101
|
-
|
102
|
-
return self.authorization
|
103
|
-
end
|
183
|
+
# @return [HTTPAdapter]
|
184
|
+
# The HTTP adapter object. The object must include the
|
185
|
+
# HTTPAdapter module and conform to its interface.
|
186
|
+
attr_reader :http_adapter
|
104
187
|
|
105
188
|
##
|
106
189
|
# Returns the HTTP adapter used by the client.
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
190
|
+
#
|
191
|
+
# @return [HTTPAdapter]
|
192
|
+
# The HTTP adapter object. The object must include the
|
193
|
+
# HTTPAdapter module and conform to its interface.
|
194
|
+
def http_adapter=(new_http_adapter)
|
195
|
+
if new_http_adapter.kind_of?(HTTPAdapter)
|
196
|
+
@http_adapter = new_http_adapter
|
197
|
+
else
|
198
|
+
raise TypeError, "Expected HTTPAdapter, got #{new_http_adapter.class}."
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
202
|
+
##
|
203
|
+
# The API hostname used by the client.
|
204
|
+
#
|
205
|
+
# @return [String]
|
206
|
+
# The API hostname. Should almost always be 'www.googleapis.com'.
|
207
|
+
attr_accessor :host
|
208
|
+
|
209
|
+
##
|
210
|
+
# The user agent used by the client.
|
211
|
+
#
|
212
|
+
# @return [String]
|
213
|
+
# The user agent string used in the User-Agent header.
|
214
|
+
attr_accessor :user_agent
|
215
|
+
|
216
|
+
##
|
217
|
+
# Returns the URI for the directory document.
|
218
|
+
#
|
219
|
+
# @return [Addressable::URI] The URI of the directory document.
|
220
|
+
def directory_uri
|
221
|
+
template = Addressable::Template.new(
|
222
|
+
"https://{host}/discovery/v1/apis"
|
223
|
+
)
|
224
|
+
return template.expand({"host" => self.host})
|
225
|
+
end
|
226
|
+
|
227
|
+
##
|
228
|
+
# Manually registers a URI as a discovery document for a specific version
|
229
|
+
# of an API.
|
230
|
+
#
|
231
|
+
# @param [String, Symbol] api The service name.
|
232
|
+
# @param [String] version The desired version of the service.
|
233
|
+
# @param [Addressable::URI] uri The URI of the discovery document.
|
234
|
+
def register_discovery_uri(api, version, uri)
|
235
|
+
api = api.to_s
|
236
|
+
version = version || 'v1'
|
237
|
+
@discovery_uris["#{api}:#{version}"] = uri
|
112
238
|
end
|
113
239
|
|
114
240
|
##
|
115
241
|
# Returns the URI for the discovery document.
|
116
242
|
#
|
243
|
+
# @param [String, Symbol] api The service name.
|
244
|
+
# @param [String] version The desired version of the service.
|
117
245
|
# @return [Addressable::URI] The URI of the discovery document.
|
118
|
-
def discovery_uri
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
246
|
+
def discovery_uri(api, version=nil)
|
247
|
+
api = api.to_s
|
248
|
+
version = version || 'v1'
|
249
|
+
return @discovery_uris["#{api}:#{version}"] ||= (begin
|
250
|
+
template = Addressable::Template.new(
|
251
|
+
"https://{host}/discovery/v1/apis/" +
|
252
|
+
"{api}/{version}/rest"
|
253
|
+
)
|
254
|
+
template.expand({
|
255
|
+
"host" => self.host,
|
256
|
+
"api" => api,
|
257
|
+
"version" => version
|
258
|
+
})
|
131
259
|
end)
|
132
260
|
end
|
133
261
|
|
134
262
|
##
|
135
|
-
#
|
263
|
+
# Manually registers a pre-loaded discovery document for a specific version
|
264
|
+
# of an API.
|
136
265
|
#
|
137
|
-
# @param [
|
138
|
-
#
|
139
|
-
|
140
|
-
|
266
|
+
# @param [String, Symbol] api The service name.
|
267
|
+
# @param [String] version The desired version of the service.
|
268
|
+
# @param [String, StringIO] discovery_document
|
269
|
+
# The contents of the discovery document.
|
270
|
+
def register_discovery_document(api, version, discovery_document)
|
271
|
+
api = api.to_s
|
272
|
+
version = version || 'v1'
|
273
|
+
if discovery_document.kind_of?(StringIO)
|
274
|
+
discovery_document.rewind
|
275
|
+
discovery_document = discovery_document.string
|
276
|
+
elsif discovery_document.respond_to?(:to_str)
|
277
|
+
discovery_document = discovery_document.to_str
|
278
|
+
else
|
279
|
+
raise TypeError,
|
280
|
+
"Expected String or StringIO, got #{discovery_document.class}."
|
281
|
+
end
|
282
|
+
@discovery_documents["#{api}:#{version}"] =
|
283
|
+
JSON.parse(discovery_document)
|
284
|
+
end
|
285
|
+
|
286
|
+
##
|
287
|
+
# Returns the parsed directory document.
|
288
|
+
#
|
289
|
+
# @return [Hash] The parsed JSON from the directory document.
|
290
|
+
def directory_document
|
291
|
+
return @directory_document ||= (begin
|
292
|
+
request_uri = self.directory_uri
|
293
|
+
request = ['GET', request_uri, [], []]
|
294
|
+
response = self.transmit_request(request)
|
295
|
+
status, headers, body = response
|
296
|
+
if status == 200 # TODO(bobaman) Better status code handling?
|
297
|
+
merged_body = StringIO.new
|
298
|
+
body.each do |chunk|
|
299
|
+
merged_body.write(chunk)
|
300
|
+
end
|
301
|
+
merged_body.rewind
|
302
|
+
JSON.parse(merged_body.string)
|
303
|
+
else
|
304
|
+
raise TransmissionError,
|
305
|
+
"Could not retrieve discovery document at: #{request_uri}"
|
306
|
+
end
|
307
|
+
end)
|
141
308
|
end
|
142
309
|
|
143
310
|
##
|
144
311
|
# Returns the parsed discovery document.
|
145
312
|
#
|
313
|
+
# @param [String, Symbol] api The service name.
|
314
|
+
# @param [String] version The desired version of the service.
|
146
315
|
# @return [Hash] The parsed JSON from the discovery document.
|
147
|
-
def discovery_document
|
148
|
-
|
149
|
-
|
316
|
+
def discovery_document(api, version=nil)
|
317
|
+
api = api.to_s
|
318
|
+
version = version || 'v1'
|
319
|
+
return @discovery_documents["#{api}:#{version}"] ||= (begin
|
320
|
+
request_uri = self.discovery_uri(api, version)
|
321
|
+
request = ['GET', request_uri, [], []]
|
150
322
|
response = self.transmit_request(request)
|
151
323
|
status, headers, body = response
|
152
324
|
if status == 200 # TODO(bobaman) Better status code handling?
|
@@ -158,101 +330,102 @@ module Google
|
|
158
330
|
JSON.parse(merged_body.string)
|
159
331
|
else
|
160
332
|
raise TransmissionError,
|
161
|
-
"Could not retrieve discovery document at: #{
|
333
|
+
"Could not retrieve discovery document at: #{request_uri}"
|
162
334
|
end
|
163
335
|
end)
|
164
336
|
end
|
165
337
|
|
166
338
|
##
|
167
|
-
# Returns
|
168
|
-
#
|
169
|
-
#
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
for service_version in versions.keys()
|
179
|
-
service_description =
|
180
|
-
self.discovery_document['data'][service_name][service_version]
|
181
|
-
services << ::Google::APIClient::Service.new(
|
182
|
-
service_name,
|
183
|
-
service_version,
|
184
|
-
service_description
|
339
|
+
# Returns all APIs published in the directory document.
|
340
|
+
#
|
341
|
+
# @return [Array] The list of available APIs.
|
342
|
+
def discovered_apis
|
343
|
+
@directory_apis ||= (begin
|
344
|
+
document_base = self.directory_uri
|
345
|
+
if self.directory_document && self.directory_document['items']
|
346
|
+
self.directory_document['items'].map do |discovery_document|
|
347
|
+
::Google::APIClient::API.new(
|
348
|
+
document_base,
|
349
|
+
discovery_document
|
185
350
|
)
|
186
351
|
end
|
352
|
+
else
|
353
|
+
[]
|
187
354
|
end
|
188
|
-
services
|
189
355
|
end)
|
190
356
|
end
|
191
357
|
|
192
358
|
##
|
193
359
|
# Returns the service object for a given service name and service version.
|
194
360
|
#
|
195
|
-
# @param [String, Symbol]
|
196
|
-
# @param [String]
|
361
|
+
# @param [String, Symbol] api The service name.
|
362
|
+
# @param [String] version The desired version of the service.
|
197
363
|
#
|
198
|
-
# @return [Google::APIClient::
|
199
|
-
def
|
200
|
-
if !
|
364
|
+
# @return [Google::APIClient::API] The service object.
|
365
|
+
def discovered_api(api, version=nil)
|
366
|
+
if !api.kind_of?(String) && !api.kind_of?(Symbol)
|
201
367
|
raise TypeError,
|
202
|
-
"Expected String or Symbol, got #{
|
368
|
+
"Expected String or Symbol, got #{api.class}."
|
203
369
|
end
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
370
|
+
api = api.to_s
|
371
|
+
version = version || 'v1'
|
372
|
+
return @discovered_apis["#{api}:#{version}"] ||= begin
|
373
|
+
document_base = self.discovery_uri(api, version)
|
374
|
+
discovery_document = self.discovery_document(api, version)
|
375
|
+
if document_base && discovery_document
|
376
|
+
::Google::APIClient::API.new(
|
377
|
+
document_base,
|
378
|
+
discovery_document
|
379
|
+
)
|
380
|
+
else
|
381
|
+
nil
|
209
382
|
end
|
210
383
|
end
|
211
|
-
return nil
|
212
384
|
end
|
213
385
|
|
214
386
|
##
|
215
387
|
# Returns the method object for a given RPC name and service version.
|
216
388
|
#
|
217
389
|
# @param [String, Symbol] rpc_name The RPC name of the desired method.
|
218
|
-
# @param [String]
|
390
|
+
# @param [String] version The desired version of the service.
|
219
391
|
#
|
220
392
|
# @return [Google::APIClient::Method] The method object.
|
221
|
-
def discovered_method(rpc_name,
|
393
|
+
def discovered_method(rpc_name, api, version=nil)
|
222
394
|
if !rpc_name.kind_of?(String) && !rpc_name.kind_of?(Symbol)
|
223
395
|
raise TypeError,
|
224
396
|
"Expected String or Symbol, got #{rpc_name.class}."
|
225
397
|
end
|
226
398
|
rpc_name = rpc_name.to_s
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
399
|
+
api = api.to_s
|
400
|
+
version = version || 'v1'
|
401
|
+
service = self.discovered_api(api, version)
|
402
|
+
if service.to_h[rpc_name]
|
403
|
+
return service.to_h[rpc_name]
|
404
|
+
else
|
405
|
+
return nil
|
233
406
|
end
|
234
|
-
return nil
|
235
407
|
end
|
236
408
|
|
237
409
|
##
|
238
410
|
# Returns the service object with the highest version number.
|
239
411
|
#
|
240
|
-
# <em>Warning</em>: This method should be used with great care.
|
241
|
-
# are updated, minor differences between versions may cause
|
412
|
+
# @note <em>Warning</em>: This method should be used with great care.
|
413
|
+
# As APIs are updated, minor differences between versions may cause
|
242
414
|
# incompatibilities. Requesting a specific version will avoid this issue.
|
243
415
|
#
|
244
|
-
# @param [String, Symbol]
|
416
|
+
# @param [String, Symbol] api The name of the service.
|
245
417
|
#
|
246
|
-
# @return [Google::APIClient::
|
247
|
-
def
|
248
|
-
if !
|
418
|
+
# @return [Google::APIClient::API] The service object.
|
419
|
+
def preferred_version(api)
|
420
|
+
if !api.kind_of?(String) && !api.kind_of?(Symbol)
|
249
421
|
raise TypeError,
|
250
|
-
"Expected String or Symbol, got #{
|
422
|
+
"Expected String or Symbol, got #{api.class}."
|
423
|
+
end
|
424
|
+
api = api.to_s
|
425
|
+
# TODO(bobaman): Update to use directory API.
|
426
|
+
return self.discovered_apis.detect do |a|
|
427
|
+
a.name == api && a.preferred == true
|
251
428
|
end
|
252
|
-
service_name = service_name.to_s
|
253
|
-
return (self.discovered_services.select do |service|
|
254
|
-
service.name == service_name
|
255
|
-
end).sort.last
|
256
429
|
end
|
257
430
|
|
258
431
|
##
|
@@ -266,16 +439,17 @@ module Google
|
|
266
439
|
# @param [Hash, Array] headers The HTTP headers for the request.
|
267
440
|
# @param [Hash] options
|
268
441
|
# The configuration parameters for the request.
|
269
|
-
# - <code>:
|
442
|
+
# - <code>:version</code> —
|
270
443
|
# The service version. Only used if <code>api_method</code> is a
|
271
444
|
# <code>String</code>. Defaults to <code>'v1'</code>.
|
272
445
|
# - <code>:parser</code> —
|
273
446
|
# The parser for the response.
|
274
447
|
# - <code>:authorization</code> —
|
275
448
|
# The authorization mechanism for the response. Used only if
|
276
|
-
# <code>:
|
277
|
-
# - <code>:
|
278
|
-
# <code>true</code> if the request must be signed
|
449
|
+
# <code>:authenticated</code> is <code>true</code>.
|
450
|
+
# - <code>:authenticated</code> —
|
451
|
+
# <code>true</code> if the request must be signed or otherwise
|
452
|
+
# authenticated, <code>false</code>
|
279
453
|
# otherwise. Defaults to <code>true</code> if an authorization
|
280
454
|
# mechanism has been set, <code>false</code> otherwise.
|
281
455
|
#
|
@@ -291,19 +465,27 @@ module Google
|
|
291
465
|
api_method, parameters={}, body='', headers=[], options={})
|
292
466
|
options={
|
293
467
|
:parser => self.parser,
|
294
|
-
:
|
468
|
+
:version => 'v1',
|
295
469
|
:authorization => self.authorization
|
296
470
|
}.merge(options)
|
297
|
-
# The default value for the :
|
471
|
+
# The default value for the :authenticated option depends on whether an
|
298
472
|
# authorization mechanism has been set.
|
299
473
|
if options[:authorization]
|
300
|
-
options = {:
|
474
|
+
options = {:authenticated => true}.merge(options)
|
301
475
|
else
|
302
|
-
options = {:
|
476
|
+
options = {:authenticated => false}.merge(options)
|
303
477
|
end
|
304
478
|
if api_method.kind_of?(String) || api_method.kind_of?(Symbol)
|
479
|
+
api_method = api_method.to_s
|
480
|
+
# This method of guessing the API is unreliable. This will fail for
|
481
|
+
# APIs where the first segment of the RPC name does not match the
|
482
|
+
# service name. However, this is a fallback mechanism anyway.
|
483
|
+
# Developers should be passing in a reference to the method, rather
|
484
|
+
# than passing in a string or symbol. This should raise an error
|
485
|
+
# in the case of a mismatch.
|
486
|
+
api = api_method[/^([^.]+)\./, 1]
|
305
487
|
api_method = self.discovered_method(
|
306
|
-
api_method
|
488
|
+
api_method, api, options[:version]
|
307
489
|
)
|
308
490
|
elsif !api_method.kind_of?(::Google::APIClient::Method)
|
309
491
|
raise TypeError,
|
@@ -314,8 +496,8 @@ module Google
|
|
314
496
|
raise ArgumentError, "API method could not be found."
|
315
497
|
end
|
316
498
|
request = api_method.generate_request(parameters, body, headers)
|
317
|
-
if options[:
|
318
|
-
request = self.
|
499
|
+
if options[:authenticated]
|
500
|
+
request = self.generate_authenticated_request(:request => request)
|
319
501
|
end
|
320
502
|
return request
|
321
503
|
end
|
@@ -331,7 +513,7 @@ module Google
|
|
331
513
|
# @param [Hash, Array] headers The HTTP headers for the request.
|
332
514
|
# @param [Hash] options
|
333
515
|
# The configuration parameters for the request.
|
334
|
-
# - <code>:
|
516
|
+
# - <code>:version</code> —
|
335
517
|
# The service version. Only used if <code>api_method</code> is a
|
336
518
|
# <code>String</code>. Defaults to <code>'v1'</code>.
|
337
519
|
# - <code>:adapter</code> —
|
@@ -340,9 +522,10 @@ module Google
|
|
340
522
|
# The parser for the response.
|
341
523
|
# - <code>:authorization</code> —
|
342
524
|
# The authorization mechanism for the response. Used only if
|
343
|
-
# <code>:
|
344
|
-
# - <code>:
|
345
|
-
# <code>true</code> if the request must be signed
|
525
|
+
# <code>:authenticated</code> is <code>true</code>.
|
526
|
+
# - <code>:authenticated</code> —
|
527
|
+
# <code>true</code> if the request must be signed or otherwise
|
528
|
+
# authenticated, <code>false</code>
|
346
529
|
# otherwise. Defaults to <code>true</code>.
|
347
530
|
#
|
348
531
|
# @return [Array] The response from the API.
|
@@ -371,21 +554,36 @@ module Google
|
|
371
554
|
#
|
372
555
|
# @return [Array] The response from the server.
|
373
556
|
def transmit_request(request, adapter=self.http_adapter)
|
374
|
-
|
557
|
+
if self.user_agent != nil
|
558
|
+
# If there's no User-Agent header, set one.
|
559
|
+
method, uri, headers, body = request
|
560
|
+
unless headers.kind_of?(Enumerable)
|
561
|
+
# We need to use some Enumerable methods, relying on the presence of
|
562
|
+
# the #each method.
|
563
|
+
class <<headers
|
564
|
+
include Enumerable
|
565
|
+
end
|
566
|
+
end
|
567
|
+
if self.user_agent.kind_of?(String)
|
568
|
+
unless headers.any? { |k, v| k.downcase == 'User-Agent'.downcase }
|
569
|
+
headers = headers.to_a.insert(0, ['User-Agent', self.user_agent])
|
570
|
+
end
|
571
|
+
elsif self.user_agent != nil
|
572
|
+
raise TypeError,
|
573
|
+
"Expected User-Agent to be String, got #{self.user_agent.class}"
|
574
|
+
end
|
575
|
+
end
|
576
|
+
adapter.transmit([method, uri, headers, body])
|
375
577
|
end
|
376
578
|
|
377
579
|
##
|
378
580
|
# Signs a request using the current authorization mechanism.
|
379
581
|
#
|
380
|
-
# @param [
|
381
|
-
# @param [#generate_authenticated_request] authorization
|
382
|
-
# The authorization mechanism.
|
582
|
+
# @param [Hash] options The options to pass through.
|
383
583
|
#
|
384
|
-
# @return [Array] The signed request.
|
385
|
-
def
|
386
|
-
return authorization.generate_authenticated_request(
|
387
|
-
:request => request
|
388
|
-
)
|
584
|
+
# @return [Array] The signed or otherwise authenticated request.
|
585
|
+
def generate_authenticated_request(options={})
|
586
|
+
return authorization.generate_authenticated_request(options)
|
389
587
|
end
|
390
588
|
end
|
391
589
|
end
|