google-api-client 0.1.3 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|