google-api-client 0.4.7 → 0.5.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.md +11 -0
- data/Gemfile +6 -1
- data/Gemfile.lock +80 -0
- data/README.md +152 -45
- data/Rakefile +2 -2
- data/bin/google-api +2 -9
- data/lib/compat/multi_json.rb +2 -3
- data/lib/google/api_client.rb +87 -278
- data/lib/google/api_client/auth/jwt_asserter.rb +139 -0
- data/lib/google/api_client/auth/pkcs12.rb +48 -0
- data/lib/google/api_client/batch.rb +164 -136
- data/lib/google/api_client/client_secrets.rb +45 -1
- data/lib/google/api_client/discovery/api.rb +7 -8
- data/lib/google/api_client/discovery/method.rb +20 -27
- data/lib/google/api_client/discovery/resource.rb +16 -10
- data/lib/google/api_client/discovery/schema.rb +2 -0
- data/lib/google/api_client/media.rb +76 -64
- data/lib/google/api_client/reference.rb +7 -285
- data/lib/google/api_client/request.rb +336 -0
- data/lib/google/api_client/result.rb +147 -55
- data/lib/google/api_client/service_account.rb +2 -120
- data/lib/google/api_client/version.rb +2 -3
- data/spec/google/api_client/batch_spec.rb +9 -10
- data/spec/google/api_client/discovery_spec.rb +184 -114
- data/spec/google/api_client/media_spec.rb +27 -39
- data/spec/google/api_client/result_spec.rb +30 -11
- data/spec/google/api_client/service_account_spec.rb +38 -6
- data/spec/google/api_client_spec.rb +48 -32
- data/spec/spec_helper.rb +46 -0
- data/tasks/gem.rake +1 -0
- metadata +36 -70
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,14 @@
|
|
1
|
+
# 0.5.0
|
2
|
+
|
3
|
+
* Beta candidate, potential incompatible changes with how requests are processed.
|
4
|
+
* All requests should be made using execute() or execute!()
|
5
|
+
* :api_method in request can no longer be a string
|
6
|
+
* Deprecated ResumableUpload.send_* methods.
|
7
|
+
* Reduce memory utilization when uploading large files
|
8
|
+
* Automatic refresh of OAuth 2 credentials & retry of request when 401 errors
|
9
|
+
are returned
|
10
|
+
* Simplify internal request processing.
|
11
|
+
|
1
12
|
# 0.4.7
|
2
13
|
|
3
14
|
* Added the ability to convert client secrets to an authorization object
|
data/Gemfile
CHANGED
@@ -9,12 +9,17 @@ gem 'autoparse', '>= 0.3.2'
|
|
9
9
|
gem 'faraday', '~> 0.8.1'
|
10
10
|
gem 'multi_json', '>= 1.0.0'
|
11
11
|
gem 'extlib', '>= 0.9.15'
|
12
|
+
gem 'jwt', '~> 0.1.5'
|
12
13
|
gem 'jruby-openssl', :platforms => :jruby
|
13
14
|
|
14
15
|
group :development do
|
15
16
|
gem 'launchy', '>= 2.1.1'
|
16
17
|
gem 'yard'
|
17
|
-
|
18
|
+
if File.exist?('/usr/bin/gcc-4.2')
|
19
|
+
# Not a critically important gem to have around.
|
20
|
+
# If it's not going to build, skip it.
|
21
|
+
gem 'redcarpet'
|
22
|
+
end
|
18
23
|
end
|
19
24
|
|
20
25
|
group :examples do
|
data/Gemfile.lock
ADDED
@@ -0,0 +1,80 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
google-api-client (0.5.0)
|
5
|
+
addressable (>= 2.3.2)
|
6
|
+
autoparse (>= 0.3.2)
|
7
|
+
extlib (>= 0.9.15)
|
8
|
+
faraday (~> 0.8.1)
|
9
|
+
jwt (>= 0.1.5)
|
10
|
+
launchy (>= 2.1.1)
|
11
|
+
multi_json (>= 1.0.0)
|
12
|
+
signet (>= 0.4.1)
|
13
|
+
uuidtools (>= 2.1.0)
|
14
|
+
|
15
|
+
GEM
|
16
|
+
remote: http://rubygems.org/
|
17
|
+
specs:
|
18
|
+
addressable (2.3.2)
|
19
|
+
autoparse (0.3.2)
|
20
|
+
addressable (>= 2.3.1)
|
21
|
+
extlib (>= 0.9.15)
|
22
|
+
multi_json (>= 1.0.0)
|
23
|
+
diff-lcs (1.1.3)
|
24
|
+
extlib (0.9.15)
|
25
|
+
faraday (0.8.4)
|
26
|
+
multipart-post (~> 1.1)
|
27
|
+
idn (0.0.2)
|
28
|
+
jwt (0.1.5)
|
29
|
+
multi_json (>= 1.0)
|
30
|
+
launchy (2.1.2)
|
31
|
+
addressable (~> 2.3)
|
32
|
+
multi_json (1.3.6)
|
33
|
+
multipart-post (1.1.5)
|
34
|
+
rack (1.4.1)
|
35
|
+
rack-protection (1.2.0)
|
36
|
+
rack
|
37
|
+
rake (0.9.2.2)
|
38
|
+
rcov (1.0.0)
|
39
|
+
rspec (2.11.0)
|
40
|
+
rspec-core (~> 2.11.0)
|
41
|
+
rspec-expectations (~> 2.11.0)
|
42
|
+
rspec-mocks (~> 2.11.0)
|
43
|
+
rspec-core (2.11.1)
|
44
|
+
rspec-expectations (2.11.3)
|
45
|
+
diff-lcs (~> 1.1.3)
|
46
|
+
rspec-mocks (2.11.3)
|
47
|
+
signet (0.4.3)
|
48
|
+
addressable (>= 2.2.3)
|
49
|
+
faraday (~> 0.8.1)
|
50
|
+
jwt (>= 0.1.5)
|
51
|
+
multi_json (>= 1.0.0)
|
52
|
+
sinatra (1.3.3)
|
53
|
+
rack (~> 1.3, >= 1.3.6)
|
54
|
+
rack-protection (~> 1.2)
|
55
|
+
tilt (~> 1.3, >= 1.3.3)
|
56
|
+
tilt (1.3.3)
|
57
|
+
uuidtools (2.1.3)
|
58
|
+
yard (0.8.3)
|
59
|
+
|
60
|
+
PLATFORMS
|
61
|
+
ruby
|
62
|
+
|
63
|
+
DEPENDENCIES
|
64
|
+
addressable (>= 2.3.2)
|
65
|
+
autoparse (>= 0.3.2)
|
66
|
+
extlib (>= 0.9.15)
|
67
|
+
faraday (~> 0.8.1)
|
68
|
+
google-api-client!
|
69
|
+
idn
|
70
|
+
jruby-openssl
|
71
|
+
jwt (~> 0.1.5)
|
72
|
+
launchy (>= 2.1.1)
|
73
|
+
multi_json (>= 1.0.0)
|
74
|
+
rake (>= 0.9.0)
|
75
|
+
rcov (>= 0.9.9)
|
76
|
+
rspec (>= 2.11.0)
|
77
|
+
signet (>= 0.4.1)
|
78
|
+
sinatra
|
79
|
+
uuidtools (>= 2.1.0)
|
80
|
+
yard
|
data/README.md
CHANGED
@@ -1,8 +1,8 @@
|
|
1
|
-
#
|
1
|
+
# Google API Client
|
2
2
|
|
3
3
|
<dl>
|
4
4
|
<dt>Homepage</dt><dd><a href="http://code.google.com/p/google-api-ruby-client">http://code.google.com/p/google-api-ruby-client</a></dd>
|
5
|
-
<dt>
|
5
|
+
<dt>Authoris</dt><dd>Bob Aman, <a href="mailto:sbazyl@google.com">Steven Bazyl</a></dd>
|
6
6
|
<dt>Copyright</dt><dd>Copyright © 2011 Google, Inc.</dd>
|
7
7
|
<dt>License</dt><dd>Apache 2.0</dd>
|
8
8
|
</dl>
|
@@ -10,62 +10,169 @@
|
|
10
10
|
[](http://travis-ci.org/google/google-api-ruby-client)
|
11
11
|
[](https://gemnasium.com/google/google-api-ruby-client)
|
12
12
|
|
13
|
-
|
13
|
+
## Description
|
14
14
|
|
15
15
|
The Google API Ruby Client makes it trivial to discover and access supported
|
16
16
|
APIs.
|
17
17
|
|
18
|
-
|
18
|
+
## Install
|
19
19
|
|
20
|
-
|
20
|
+
Be sure `http://rubygems.org/` is in your gem sources.
|
21
|
+
|
22
|
+
For normal client usage, this is sufficient:
|
23
|
+
|
24
|
+
$ sudo gem install google-api-client
|
25
|
+
|
26
|
+
The command line interface, the example applications, and the test suite
|
27
|
+
require additional dependencies. These may be obtained with:
|
28
|
+
|
29
|
+
$ sudo gem install google-api-client --development --force --no-rdoc --no-ri
|
30
|
+
|
31
|
+
## Example Usage
|
32
|
+
|
33
|
+
# Initialize the client & Google+ API
|
21
34
|
require 'google/api_client'
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
:authorization_uri =>
|
30
|
-
'https://www.google.com/buzz/api/auth/OAuthAuthorizeToken',
|
31
|
-
:token_credential_uri =>
|
32
|
-
'https://www.google.com/accounts/OAuthGetAccessToken',
|
33
|
-
:client_credential_key => 'anonymous',
|
34
|
-
:client_credential_secret => 'anonymous'
|
35
|
-
)
|
36
|
-
)
|
37
|
-
client.authorization.fetch_temporary_credential!(
|
38
|
-
:additional_parameters => {
|
39
|
-
'scope' => 'https://www.googleapis.com/auth/buzz'
|
40
|
-
}
|
41
|
-
)
|
42
|
-
redirect_uri = client.authorization.authorization_uri(
|
43
|
-
:additional_parameters => {
|
44
|
-
'domain' => client.authorization.client_credential_key,
|
45
|
-
'scope' => 'https://www.googleapis.com/auth/buzz'
|
46
|
-
}
|
47
|
-
)
|
48
|
-
# Redirect user here
|
49
|
-
client.authorization.fetch_token_credential!(:verifier => '12345')
|
50
|
-
|
51
|
-
# Discover available methods
|
52
|
-
method_names = client.discovered_api('plus').to_h.keys
|
35
|
+
client = Google::APIClient.new
|
36
|
+
plus = client.discovered_api('plus')
|
37
|
+
|
38
|
+
# Initialize OAuth 2.0 client
|
39
|
+
client.authorization.client_id = '<CLIENT_ID_FROM_API_CONSOLE>'
|
40
|
+
client.authorization.client_secret = '<CLIENT_SECRET>'
|
41
|
+
client.authorization.redirect_uri = '<YOUR_REDIRECT_URI>'
|
53
42
|
|
43
|
+
client.authorization.scope = 'https://www.googleapis.com/auth/plus.me'
|
44
|
+
|
45
|
+
# Request authorization
|
46
|
+
redirect_uri = client.authorization.authorization_uri
|
47
|
+
|
48
|
+
# Wait for authorization code then exchange for token
|
49
|
+
client.authorization.code = '....'
|
50
|
+
client.authorization.fetch_access_token!
|
51
|
+
|
54
52
|
# Make an API call
|
55
53
|
result = client.execute(
|
56
|
-
|
57
|
-
{'collection' => 'public', 'userId' => 'me'}
|
54
|
+
:api_method => plus.activities.list,
|
55
|
+
:parameters => {'collection' => 'public', 'userId' => 'me'}
|
58
56
|
)
|
59
57
|
|
60
|
-
|
58
|
+
puts result.data
|
61
59
|
|
62
|
-
|
60
|
+
## API Features
|
63
61
|
|
64
|
-
|
62
|
+
### API Discovery
|
63
|
+
|
64
|
+
To take full advantage of the client, load API definitions prior to use. To load an API:
|
65
|
+
|
66
|
+
urlshortener = client.discovered_api('urlshortener')
|
67
|
+
|
68
|
+
Specific versions of the API can be loaded as well:
|
69
|
+
|
70
|
+
drive = client.discovered_api('drive', 'v2')
|
71
|
+
|
72
|
+
Locally cached discovery documents may be used as well. To load an API from a local file:
|
73
|
+
|
74
|
+
doc = File.read('my-api.json')
|
75
|
+
my_api = client.register_discovery_document('myapi', 'v1', doc)
|
76
|
+
|
77
|
+
### Authorization
|
78
|
+
|
79
|
+
Most interactions with Google APIs require users to authorize applications via OAuth 2.0. The client library uses [Signet](https://github.com/google/signet) to handle most aspects of authorization. For additional details about Google's OAuth support, see [Google Developers](https://developers.google.com/accounts/docs/OAuth2).
|
80
|
+
|
81
|
+
Credentials can be managed at the connection level, as shown, or supplied on a per-request basis when calling `execute`.
|
82
|
+
|
83
|
+
For server-to-server interactions, like those between a web application and Google Cloud Storage, Prediction, or BigQuery APIs, use service accounts. Assertions for service accounts are made with `Google::APIClient::JWTAsserter`.
|
84
|
+
|
85
|
+
client = Google::APIClient.new
|
86
|
+
key = Google::APIClient::PKCS12.load_key('client.p12', 'notasecret')
|
87
|
+
service_account = Google::APIClient::JWTAsserter(
|
88
|
+
'123456-abcdef@developer.gserviceaccount.com',
|
89
|
+
'https://www.googleapis.com/auth/prediction',
|
90
|
+
key)
|
91
|
+
client.authorization = service_account.authorize
|
92
|
+
|
93
|
+
### Batching Requests
|
94
|
+
|
95
|
+
Some Google APIs support batching requests into a single HTTP request. Use `Google::APIClient::BatchRequest`
|
96
|
+
to bundle multiple requests together.
|
97
|
+
|
98
|
+
Example:
|
99
|
+
|
100
|
+
client = Google::APIClient.new
|
101
|
+
urlshortener = client.discovered_api('urlshortner')
|
102
|
+
|
103
|
+
batch = Google::APIClient::BatchRequest.new do |result|
|
104
|
+
puts result.data
|
105
|
+
end
|
106
|
+
|
107
|
+
batch.add(:api_method=>urlshortener.url.insert,
|
108
|
+
:body_object => { 'longUrl' => 'http://example.com/foo' })
|
109
|
+
batch.add(:api_method=>urlshortener.url.insert,
|
110
|
+
:body_object => { 'longUrl' => 'http://example.com/bar' })
|
111
|
+
client.execute(batch)
|
112
|
+
|
113
|
+
Blocks for handling responses can be specified either at the batch level or when adding an individual API call. For example:
|
114
|
+
|
115
|
+
batch.add(:api_method=>urlshortener.url.insert, :body_object => { 'longUrl' => 'http://example.com/bar' }) do |result|
|
116
|
+
puts result.data
|
117
|
+
end
|
118
|
+
|
119
|
+
### Media Upload
|
120
|
+
|
121
|
+
For APIs that support file uploads, use `Google::APIClient::UploadIO` to load the stream. Both multipart and resumable
|
122
|
+
uploads can be used. For example, to upload a file to Google Drive using multipart
|
123
|
+
|
124
|
+
drive = client.discovered_api('drive', 'v2')
|
125
|
+
|
126
|
+
media = Google::APIClient::UploadIO.new('mymovie.m4v', 'video/mp4')
|
127
|
+
metadata = {
|
128
|
+
'title' => 'My movie',
|
129
|
+
'description' => 'The best home movie ever made'
|
130
|
+
}
|
131
|
+
client.execute(:api_method => drive.files.insert,
|
132
|
+
:parameters => { 'uploadType' => 'multipart' },
|
133
|
+
:body_object => metadata,
|
134
|
+
:media => media )
|
135
|
+
|
136
|
+
To use resumable uploads, change the `uploadType` parameter to `resumable`. To check the status of the upload
|
137
|
+
and continue if necessary, check `result.resumable_upload`.
|
138
|
+
|
139
|
+
client.execute(:api_method => drive.files.insert,
|
140
|
+
:parameters => { 'uploadType' => 'resumable' },
|
141
|
+
:body_object => metadata,
|
142
|
+
:media => media )
|
143
|
+
upload = result.resumable_upload
|
144
|
+
|
145
|
+
# Resume if needed
|
146
|
+
if upload.resumable?
|
147
|
+
client.execute(upload)
|
148
|
+
end
|
149
|
+
|
150
|
+
## Command Line
|
151
|
+
|
152
|
+
Included with the gem is a command line interface for working with Google APIs.
|
153
|
+
|
154
|
+
# Log in
|
155
|
+
google-api oauth-2-login --client-id='...' --client-secret='...' --scope="https://www.googleapis.com/auth/plus.me"
|
156
|
+
|
157
|
+
# List the signed-in user's activities
|
158
|
+
google-api execute plus.activities.list --api=plus -- userId="me" collection="public"
|
159
|
+
|
160
|
+
# Start an interactive API session
|
161
|
+
google-api irb
|
162
|
+
>> plus = $client.discovered_api('plus')
|
163
|
+
>> $client.execute(plus.activities.list, {'userId' => 'me', 'collection' => 'public'})
|
164
|
+
=> # returns a response from the API
|
165
|
+
|
166
|
+
For more information, use `google-api --help`
|
167
|
+
|
168
|
+
## Samples
|
169
|
+
|
170
|
+
See the full list of [samples on Google Code](http://code.google.com/p/google-api-ruby-client/source/browse?repo=samples).
|
171
|
+
|
172
|
+
|
173
|
+
## Support
|
174
|
+
|
175
|
+
Please [report bugs at the project on Google Code](http://code.google.com/p/google-api-ruby-client/issues/entry). Don't hesitate to [ask questions](http://stackoverflow.com/questions/tagged/google-api) about the client or APIs on [StackOverflow](http://stackoverflow.com).
|
65
176
|
|
66
|
-
$ sudo gem install google-api-client
|
67
177
|
|
68
|
-
The command line interface, the example applications, and the test suite
|
69
|
-
require additional dependencies. These may be obtained with:
|
70
178
|
|
71
|
-
$ sudo gem install google-api-client --development --force --no-rdoc --no-ri
|
data/Rakefile
CHANGED
@@ -15,8 +15,8 @@ PKG_HOMEPAGE = 'http://code.google.com/p/google-api-ruby-client/'
|
|
15
15
|
|
16
16
|
RELEASE_NAME = "REL #{PKG_VERSION}"
|
17
17
|
|
18
|
-
PKG_AUTHOR = "Bob Aman"
|
19
|
-
PKG_AUTHOR_EMAIL = "
|
18
|
+
PKG_AUTHOR = ["Bob Aman", "Steve Bazyl"]
|
19
|
+
PKG_AUTHOR_EMAIL = "sbazyl@google.com"
|
20
20
|
PKG_SUMMARY = 'Package Summary'
|
21
21
|
PKG_DESCRIPTION = <<-TEXT
|
22
22
|
The Google API Ruby Client makes it trivial to discover and access supported
|
data/bin/google-api
CHANGED
@@ -10,11 +10,8 @@ OAUTH_SERVER_PORT = 12736
|
|
10
10
|
|
11
11
|
require 'rubygems'
|
12
12
|
require 'optparse'
|
13
|
-
|
14
|
-
gem 'faraday', '~> 0.8.1'
|
15
13
|
require 'faraday'
|
16
14
|
require 'faraday/utils'
|
17
|
-
|
18
15
|
require 'webrick'
|
19
16
|
require 'google/api_client/version'
|
20
17
|
require 'google/api_client'
|
@@ -187,7 +184,6 @@ HTML
|
|
187
184
|
end
|
188
185
|
|
189
186
|
def client
|
190
|
-
gem 'signet', '~> 0.4.0'
|
191
187
|
require 'signet/oauth_1/client'
|
192
188
|
require 'yaml'
|
193
189
|
require 'irb'
|
@@ -281,7 +277,6 @@ HTML
|
|
281
277
|
]
|
282
278
|
|
283
279
|
def oauth_1_login
|
284
|
-
gem 'signet', '~> 0.4.0'
|
285
280
|
require 'signet/oauth_1/client'
|
286
281
|
require 'launchy'
|
287
282
|
require 'yaml'
|
@@ -349,7 +344,6 @@ HTML
|
|
349
344
|
end
|
350
345
|
|
351
346
|
def oauth_2_login
|
352
|
-
gem 'signet', '~> 0.4.0'
|
353
347
|
require 'signet/oauth_2/client'
|
354
348
|
require 'launchy'
|
355
349
|
require 'yaml'
|
@@ -471,9 +465,8 @@ HTML
|
|
471
465
|
method = options[:http_method]
|
472
466
|
method ||= request_body == '' ? 'GET' : 'POST'
|
473
467
|
method.upcase!
|
474
|
-
|
475
|
-
|
476
|
-
response = client.transmit(request)
|
468
|
+
response = client.execute(:http_method => method, :uri => uri.to_str,
|
469
|
+
:headers => headers, :body => request_body)
|
477
470
|
puts response.body
|
478
471
|
exit(0)
|
479
472
|
else
|
data/lib/compat/multi_json.rb
CHANGED
@@ -1,14 +1,13 @@
|
|
1
|
-
gem 'multi_json', '>= 1.0.0'
|
2
1
|
require 'multi_json'
|
3
2
|
|
4
|
-
|
3
|
+
if !MultiJson.respond_to?(:load) || MultiJson.method(:load).owner == Kernel
|
5
4
|
module MultiJson
|
6
5
|
class <<self
|
7
6
|
alias :load :decode
|
8
7
|
end
|
9
8
|
end
|
10
9
|
end
|
11
|
-
|
10
|
+
if !MultiJson.respond_to?(:dump)
|
12
11
|
module MultiJson
|
13
12
|
class <<self
|
14
13
|
alias :dump :encode
|
data/lib/google/api_client.rb
CHANGED
@@ -13,7 +13,6 @@
|
|
13
13
|
# limitations under the License.
|
14
14
|
|
15
15
|
|
16
|
-
gem 'faraday', '~> 0.8.1'
|
17
16
|
require 'faraday'
|
18
17
|
require 'faraday/utils'
|
19
18
|
require 'multi_json'
|
@@ -24,6 +23,7 @@ require 'google/api_client/version'
|
|
24
23
|
require 'google/api_client/errors'
|
25
24
|
require 'google/api_client/environment'
|
26
25
|
require 'google/api_client/discovery'
|
26
|
+
require 'google/api_client/request'
|
27
27
|
require 'google/api_client/reference'
|
28
28
|
require 'google/api_client/result'
|
29
29
|
require 'google/api_client/media'
|
@@ -31,9 +31,6 @@ require 'google/api_client/service_account'
|
|
31
31
|
require 'google/api_client/batch'
|
32
32
|
|
33
33
|
module Google
|
34
|
-
# TODO(bobaman): Document all this stuff.
|
35
|
-
|
36
|
-
|
37
34
|
##
|
38
35
|
# This class manages APIs communication.
|
39
36
|
class APIClient
|
@@ -67,23 +64,23 @@ module Google
|
|
67
64
|
def initialize(options={})
|
68
65
|
# Normalize key to String to allow indifferent access.
|
69
66
|
options = options.inject({}) do |accu, (key, value)|
|
70
|
-
accu[key.
|
67
|
+
accu[key.to_sym] = value
|
71
68
|
accu
|
72
69
|
end
|
73
70
|
# Almost all API usage will have a host of 'www.googleapis.com'.
|
74
|
-
self.host = options[
|
75
|
-
self.port = options[
|
76
|
-
self.discovery_path = options[
|
71
|
+
self.host = options[:host] || 'www.googleapis.com'
|
72
|
+
self.port = options[:port] || 443
|
73
|
+
self.discovery_path = options[:discovery_path] || '/discovery/v1'
|
77
74
|
|
78
75
|
# Most developers will want to leave this value alone and use the
|
79
76
|
# application_name option.
|
80
77
|
application_string = (
|
81
|
-
options[
|
82
|
-
"#{options[
|
83
|
-
"#{options[
|
78
|
+
options[:application_name] ? (
|
79
|
+
"#{options[:application_name]}/" +
|
80
|
+
"#{options[:application_version] || '0.0.0'}"
|
84
81
|
) : ""
|
85
82
|
)
|
86
|
-
self.user_agent = options[
|
83
|
+
self.user_agent = options[:user_agent] || (
|
87
84
|
"#{application_string} " +
|
88
85
|
"google-api-ruby-client/#{VERSION::STRING} " +
|
89
86
|
ENV::OS_VERSION
|
@@ -91,9 +88,9 @@ module Google
|
|
91
88
|
# The writer method understands a few Symbols and will generate useful
|
92
89
|
# default authentication mechanisms.
|
93
90
|
self.authorization =
|
94
|
-
options.key?(
|
95
|
-
self.key = options[
|
96
|
-
self.user_ip = options[
|
91
|
+
options.key?(:authorization) ? options[:authorization] : :oauth_2
|
92
|
+
self.key = options[:key]
|
93
|
+
self.user_ip = options[:user_ip]
|
97
94
|
@discovery_uris = {}
|
98
95
|
@discovery_documents = {}
|
99
96
|
@discovered_apis = {}
|
@@ -114,7 +111,6 @@ module Google
|
|
114
111
|
def authorization=(new_authorization)
|
115
112
|
case new_authorization
|
116
113
|
when :oauth_1, :oauth
|
117
|
-
gem 'signet', '~> 0.4.0'
|
118
114
|
require 'signet/oauth_1/client'
|
119
115
|
# NOTE: Do not rely on this default value, as it may change
|
120
116
|
new_authorization = Signet::OAuth1::Client.new(
|
@@ -128,7 +124,6 @@ module Google
|
|
128
124
|
:client_credential_secret => 'anonymous'
|
129
125
|
)
|
130
126
|
when :two_legged_oauth_1, :two_legged_oauth
|
131
|
-
gem 'signet', '~> 0.4.0'
|
132
127
|
require 'signet/oauth_1/client'
|
133
128
|
# NOTE: Do not rely on this default value, as it may change
|
134
129
|
new_authorization = Signet::OAuth1::Client.new(
|
@@ -137,7 +132,6 @@ module Google
|
|
137
132
|
:two_legged => true
|
138
133
|
)
|
139
134
|
when :oauth_2
|
140
|
-
gem 'signet', '~> 0.4.0'
|
141
135
|
require 'signet/oauth_2/client'
|
142
136
|
# NOTE: Do not rely on this default value, as it may change
|
143
137
|
new_authorization = Signet::OAuth2::Client.new(
|
@@ -199,31 +193,6 @@ module Google
|
|
199
193
|
# The base path. Should almost always be '/discovery/v1'.
|
200
194
|
attr_accessor :discovery_path
|
201
195
|
|
202
|
-
##
|
203
|
-
# Resolves a URI template against the client's configured base.
|
204
|
-
#
|
205
|
-
# @param [String, Addressable::URI, Addressable::Template] template
|
206
|
-
# The template to resolve.
|
207
|
-
# @param [Hash] mapping The mapping that corresponds to the template.
|
208
|
-
# @return [Addressable::URI] The expanded URI.
|
209
|
-
def resolve_uri(template, mapping={})
|
210
|
-
@base_uri ||= Addressable::URI.new(
|
211
|
-
:scheme => 'https',
|
212
|
-
:host => self.host,
|
213
|
-
:port => self.port
|
214
|
-
).normalize
|
215
|
-
template = if template.kind_of?(Addressable::Template)
|
216
|
-
template.pattern
|
217
|
-
elsif template.respond_to?(:to_str)
|
218
|
-
template.to_str
|
219
|
-
else
|
220
|
-
raise TypeError,
|
221
|
-
"Expected String, Addressable::URI, or Addressable::Template, " +
|
222
|
-
"got #{template.class}."
|
223
|
-
end
|
224
|
-
return Addressable::Template.new(@base_uri + template).expand(mapping)
|
225
|
-
end
|
226
|
-
|
227
196
|
##
|
228
197
|
# Returns the URI for the directory document.
|
229
198
|
#
|
@@ -293,27 +262,12 @@ module Google
|
|
293
262
|
# @return [Hash] The parsed JSON from the directory document.
|
294
263
|
def directory_document
|
295
264
|
return @directory_document ||= (begin
|
296
|
-
|
265
|
+
response = self.execute!(
|
297
266
|
:http_method => :get,
|
298
267
|
:uri => self.directory_uri,
|
299
268
|
:authenticated => false
|
300
269
|
)
|
301
|
-
response
|
302
|
-
if response.status >= 200 && response.status < 300
|
303
|
-
MultiJson.load(response.body)
|
304
|
-
elsif response.status >= 400
|
305
|
-
case response.status
|
306
|
-
when 400...500
|
307
|
-
exception_type = ClientError
|
308
|
-
when 500...600
|
309
|
-
exception_type = ServerError
|
310
|
-
else
|
311
|
-
exception_type = TransmissionError
|
312
|
-
end
|
313
|
-
url = request.to_env(Faraday.default_connection)[:url]
|
314
|
-
raise exception_type,
|
315
|
-
"Could not retrieve directory document at: #{url}"
|
316
|
-
end
|
270
|
+
response.data
|
317
271
|
end)
|
318
272
|
end
|
319
273
|
|
@@ -327,27 +281,12 @@ module Google
|
|
327
281
|
api = api.to_s
|
328
282
|
version = version || 'v1'
|
329
283
|
return @discovery_documents["#{api}:#{version}"] ||= (begin
|
330
|
-
|
284
|
+
response = self.execute!(
|
331
285
|
:http_method => :get,
|
332
286
|
:uri => self.discovery_uri(api, version),
|
333
287
|
:authenticated => false
|
334
288
|
)
|
335
|
-
response
|
336
|
-
if response.status >= 200 && response.status < 300
|
337
|
-
MultiJson.load(response.body)
|
338
|
-
elsif response.status >= 400
|
339
|
-
case response.status
|
340
|
-
when 400...500
|
341
|
-
exception_type = ClientError
|
342
|
-
when 500...600
|
343
|
-
exception_type = ServerError
|
344
|
-
else
|
345
|
-
exception_type = TransmissionError
|
346
|
-
end
|
347
|
-
url = request.to_env(Faraday.default_connection)[:url]
|
348
|
-
raise exception_type,
|
349
|
-
"Could not retrieve discovery document at: #{url}"
|
350
|
-
end
|
289
|
+
response.data
|
351
290
|
end)
|
352
291
|
end
|
353
292
|
|
@@ -403,7 +342,7 @@ module Google
|
|
403
342
|
# Returns the method object for a given RPC name and service version.
|
404
343
|
#
|
405
344
|
# @param [String, Symbol] rpc_name The RPC name of the desired method.
|
406
|
-
# @param [String, Symbol]
|
345
|
+
# @param [String, Symbol] api The API the method is within.
|
407
346
|
# @param [String] version The desired version of the API.
|
408
347
|
#
|
409
348
|
# @return [Google::APIClient::Method] The method object.
|
@@ -449,7 +388,6 @@ module Google
|
|
449
388
|
# an ID token supplied by an untrusted client-side mechanism is valid.
|
450
389
|
# Raises an error if the token is invalid or missing.
|
451
390
|
def verify_id_token!
|
452
|
-
gem 'jwt', '~> 0.1.4'
|
453
391
|
require 'jwt'
|
454
392
|
require 'openssl'
|
455
393
|
@certificates ||= {}
|
@@ -479,31 +417,16 @@ module Google
|
|
479
417
|
if check_cached_certs.call()
|
480
418
|
return true
|
481
419
|
end
|
482
|
-
|
420
|
+
response = self.execute!(
|
483
421
|
:http_method => :get,
|
484
422
|
:uri => 'https://www.googleapis.com/oauth2/v1/certs',
|
485
423
|
:authenticated => false
|
486
424
|
)
|
487
|
-
|
488
|
-
|
489
|
-
|
490
|
-
|
491
|
-
|
492
|
-
end]
|
493
|
-
)
|
494
|
-
elsif response.status >= 400
|
495
|
-
case response.status
|
496
|
-
when 400...500
|
497
|
-
exception_type = ClientError
|
498
|
-
when 500...600
|
499
|
-
exception_type = ServerError
|
500
|
-
else
|
501
|
-
exception_type = TransmissionError
|
502
|
-
end
|
503
|
-
url = request.to_env(Faraday.default_connection)[:url]
|
504
|
-
raise exception_type,
|
505
|
-
"Could not retrieve certificates from: #{url}"
|
506
|
-
end
|
425
|
+
@certificates.merge!(
|
426
|
+
Hash[MultiJson.load(response.body).map do |key, cert|
|
427
|
+
[key, OpenSSL::X509::Certificate.new(cert)]
|
428
|
+
end]
|
429
|
+
)
|
507
430
|
if check_cached_certs.call()
|
508
431
|
return true
|
509
432
|
else
|
@@ -517,7 +440,7 @@ module Google
|
|
517
440
|
##
|
518
441
|
# Generates a request.
|
519
442
|
#
|
520
|
-
# @option options [Google::APIClient::Method
|
443
|
+
# @option options [Google::APIClient::Method] :api_method
|
521
444
|
# The method object or the RPC name of the method being executed.
|
522
445
|
# @option options [Hash, Array] :parameters
|
523
446
|
# The parameters to send to the method.
|
@@ -532,7 +455,7 @@ module Google
|
|
532
455
|
# `true` if the request must be signed or somehow
|
533
456
|
# authenticated, `false` otherwise.
|
534
457
|
#
|
535
|
-
# @return [
|
458
|
+
# @return [Google::APIClient::Reference] The generated request.
|
536
459
|
#
|
537
460
|
# @example
|
538
461
|
# request = client.generate_request(
|
@@ -541,153 +464,30 @@ module Google
|
|
541
464
|
# {'collection' => 'public', 'userId' => 'me'}
|
542
465
|
# )
|
543
466
|
def generate_request(options={})
|
544
|
-
|
545
|
-
|
546
|
-
|
547
|
-
options={
|
548
|
-
:version => 'v1',
|
549
|
-
:authorization => self.authorization,
|
550
|
-
:key => self.key,
|
551
|
-
:user_ip => self.user_ip,
|
552
|
-
:connection => Faraday.default_connection
|
467
|
+
options = {
|
468
|
+
:api_client => self
|
553
469
|
}.merge(options)
|
554
|
-
|
555
|
-
# The Reference object is going to need this to do method ID lookups.
|
556
|
-
options[:client] = self
|
557
|
-
# The default value for the :authenticated option depends on whether an
|
558
|
-
# authorization mechanism has been set.
|
559
|
-
if options[:authorization]
|
560
|
-
options = {:authenticated => true}.merge(options)
|
561
|
-
else
|
562
|
-
options = {:authenticated => false}.merge(options)
|
563
|
-
end
|
564
|
-
reference = Google::APIClient::Reference.new(options)
|
565
|
-
request = reference.to_request
|
566
|
-
if options[:authenticated]
|
567
|
-
request = options[:authorization].generate_authenticated_request(
|
568
|
-
:request => request,
|
569
|
-
:connection => options[:connection]
|
570
|
-
)
|
571
|
-
end
|
572
|
-
return request
|
573
|
-
end
|
574
|
-
|
575
|
-
##
|
576
|
-
# Signs a request using the current authorization mechanism.
|
577
|
-
#
|
578
|
-
# @param [Hash] options a customizable set of options
|
579
|
-
#
|
580
|
-
# @return [Faraday::Request] The signed or otherwise authenticated request.
|
581
|
-
# @deprecated No longer used internally
|
582
|
-
def generate_authenticated_request(options={})
|
583
|
-
return authorization.generate_authenticated_request(options)
|
584
|
-
end
|
585
|
-
|
586
|
-
##
|
587
|
-
# Transmits the request using the current HTTP adapter.
|
588
|
-
#
|
589
|
-
# @option options [Array, Faraday::Request] :request
|
590
|
-
# The HTTP request to transmit.
|
591
|
-
# @option options [String, Symbol] :method
|
592
|
-
# The method for the HTTP request.
|
593
|
-
# @option options [String, Addressable::URI] :uri
|
594
|
-
# The URI for the HTTP request.
|
595
|
-
# @option options [Array, Hash] :headers
|
596
|
-
# The headers for the HTTP request.
|
597
|
-
# @option options [String] :body
|
598
|
-
# The body for the HTTP request.
|
599
|
-
# @option options [Faraday::Connection] :connection
|
600
|
-
# The HTTP connection to use.
|
601
|
-
#
|
602
|
-
# @return [Faraday::Response] The response from the server.
|
603
|
-
def transmit(options={})
|
604
|
-
options[:connection] ||= Faraday.default_connection
|
605
|
-
if options[:request]
|
606
|
-
if options[:request].kind_of?(Array)
|
607
|
-
method, uri, headers, body = options[:request]
|
608
|
-
elsif options[:request].kind_of?(Faraday::Request)
|
609
|
-
unless options[:connection]
|
610
|
-
raise ArgumentError,
|
611
|
-
"Faraday::Request used, requires a connection to be provided."
|
612
|
-
end
|
613
|
-
method = options[:request].method.to_s.downcase.to_sym
|
614
|
-
uri = options[:connection].build_url(
|
615
|
-
options[:request].path, options[:request].params
|
616
|
-
)
|
617
|
-
headers = options[:request].headers || {}
|
618
|
-
body = options[:request].body || ''
|
619
|
-
end
|
620
|
-
else
|
621
|
-
method = options[:method] || :get
|
622
|
-
uri = options[:uri]
|
623
|
-
headers = options[:headers] || []
|
624
|
-
body = options[:body] || ''
|
625
|
-
end
|
626
|
-
headers = headers.to_a if headers.kind_of?(Hash)
|
627
|
-
request_components = {
|
628
|
-
:method => method,
|
629
|
-
:uri => uri,
|
630
|
-
:headers => headers,
|
631
|
-
:body => body
|
632
|
-
}
|
633
|
-
# Verify that we have all pieces required to transmit an HTTP request
|
634
|
-
request_components.each do |(key, value)|
|
635
|
-
unless value
|
636
|
-
raise ArgumentError, "Missing :#{key} parameter."
|
637
|
-
end
|
638
|
-
end
|
639
|
-
|
640
|
-
if self.user_agent != nil
|
641
|
-
# If there's no User-Agent header, set one.
|
642
|
-
unless headers.kind_of?(Enumerable)
|
643
|
-
# We need to use some Enumerable methods, relying on the presence of
|
644
|
-
# the #each method.
|
645
|
-
class << headers
|
646
|
-
include Enumerable
|
647
|
-
end
|
648
|
-
end
|
649
|
-
if self.user_agent.kind_of?(String)
|
650
|
-
unless headers.any? { |k, v| k.downcase == 'User-Agent'.downcase }
|
651
|
-
headers = headers.to_a.insert(0, ['User-Agent', self.user_agent])
|
652
|
-
end
|
653
|
-
elsif self.user_agent != nil
|
654
|
-
raise TypeError,
|
655
|
-
"Expected User-Agent to be String, got #{self.user_agent.class}"
|
656
|
-
end
|
657
|
-
end
|
658
|
-
|
659
|
-
request = options[:connection].build_request(
|
660
|
-
method.to_s.downcase.to_sym
|
661
|
-
) do |req|
|
662
|
-
req.url(Addressable::URI.parse(uri).normalize.to_s)
|
663
|
-
req.headers = Faraday::Utils::Headers.new(headers)
|
664
|
-
req.body = body
|
665
|
-
end
|
666
|
-
request_env = request.to_env(options[:connection])
|
667
|
-
response = options[:connection].app.call(request_env)
|
668
|
-
return response
|
470
|
+
return Google::APIClient::Request.new(options)
|
669
471
|
end
|
670
472
|
|
671
473
|
##
|
672
474
|
# Executes a request, wrapping it in a Result object.
|
673
475
|
#
|
674
|
-
# @param [Google::APIClient::
|
675
|
-
# Either a Google::APIClient::
|
476
|
+
# @param [Google::APIClient::Request, Hash, Array] params
|
477
|
+
# Either a Google::APIClient::Request, a Hash, or an Array.
|
676
478
|
#
|
677
|
-
# If a Google::APIClient::
|
479
|
+
# If a Google::APIClient::Request, no other parameters are expected.
|
678
480
|
#
|
679
481
|
# If a Hash, the below parameters are handled. If an Array, the
|
680
482
|
# parameters are assumed to be in the below order:
|
681
483
|
#
|
682
|
-
# - (Google::APIClient::Method
|
484
|
+
# - (Google::APIClient::Method) api_method:
|
683
485
|
# The method object or the RPC name of the method being executed.
|
684
486
|
# - (Hash, Array) parameters:
|
685
487
|
# The parameters to send to the method.
|
686
488
|
# - (String) body: The body of the request.
|
687
489
|
# - (Hash, Array) headers: The HTTP headers for the request.
|
688
490
|
# - (Hash) options: A set of options for the request, of which:
|
689
|
-
# - (String) :version (default: "v1") -
|
690
|
-
# The service version. Only used if `api_method` is a `String`.
|
691
491
|
# - (#generate_authenticated_request) :authorization (default: true) -
|
692
492
|
# The authorization mechanism for the response. Used only if
|
693
493
|
# `:authenticated` is `true`.
|
@@ -701,50 +501,18 @@ module Google
|
|
701
501
|
# result = client.execute(batch_request)
|
702
502
|
#
|
703
503
|
# @example
|
504
|
+
# plus = client.discovered_api('plus')
|
704
505
|
# result = client.execute(
|
705
|
-
# :api_method =>
|
506
|
+
# :api_method => plus.activities.list,
|
706
507
|
# :parameters => {'collection' => 'public', 'userId' => 'me'}
|
707
508
|
# )
|
708
509
|
#
|
709
510
|
# @see Google::APIClient#generate_request
|
710
511
|
def execute(*params)
|
711
|
-
if params.last.kind_of?(Google::APIClient::
|
512
|
+
if params.last.kind_of?(Google::APIClient::Request) &&
|
712
513
|
params.size == 1
|
713
|
-
|
714
|
-
options =
|
715
|
-
options[:connection] ||= Faraday.default_connection
|
716
|
-
http_request = batch.to_http_request
|
717
|
-
request = nil
|
718
|
-
|
719
|
-
if @authorization
|
720
|
-
method, uri, headers, body = http_request
|
721
|
-
method = method.to_s.downcase.to_sym
|
722
|
-
|
723
|
-
faraday_request = options[:connection].build_request(
|
724
|
-
method.to_s.downcase.to_sym
|
725
|
-
) do |req|
|
726
|
-
req.url(Addressable::URI.parse(uri).normalize.to_s)
|
727
|
-
req.headers = Faraday::Utils::Headers.new(headers)
|
728
|
-
req.body = body
|
729
|
-
end
|
730
|
-
|
731
|
-
request = {
|
732
|
-
:request => self.generate_authenticated_request(
|
733
|
-
:request => faraday_request,
|
734
|
-
:connection => options[:connection]
|
735
|
-
),
|
736
|
-
:connection => options[:connection]
|
737
|
-
}
|
738
|
-
else
|
739
|
-
request = {
|
740
|
-
:request => http_request,
|
741
|
-
:connection => options[:connection]
|
742
|
-
}
|
743
|
-
end
|
744
|
-
|
745
|
-
response = self.transmit(request)
|
746
|
-
batch.process_response(response)
|
747
|
-
return nil
|
514
|
+
request = params.pop
|
515
|
+
options = {}
|
748
516
|
else
|
749
517
|
# This block of code allows us to accept multiple parameter passing
|
750
518
|
# styles, and maintaining some backwards compatibility.
|
@@ -760,16 +528,28 @@ module Google
|
|
760
528
|
options[:parameters] = params.shift if params.size > 0
|
761
529
|
options[:body] = params.shift if params.size > 0
|
762
530
|
options[:headers] = params.shift if params.size > 0
|
763
|
-
options
|
764
|
-
|
765
|
-
|
766
|
-
|
767
|
-
|
768
|
-
|
769
|
-
|
770
|
-
|
771
|
-
|
531
|
+
options.update(params.shift) if params.size > 0
|
532
|
+
request = self.generate_request(options)
|
533
|
+
end
|
534
|
+
|
535
|
+
request.headers['User-Agent'] ||= '' + self.user_agent unless self.user_agent.nil?
|
536
|
+
request.parameters['key'] ||= self.key unless self.key.nil?
|
537
|
+
request.parameters['userIp'] ||= self.user_ip unless self.user_ip.nil?
|
538
|
+
|
539
|
+
connection = options[:connection] || Faraday.default_connection
|
540
|
+
request.authorization = options[:authorization] || self.authorization unless options[:authenticated] == false
|
541
|
+
|
542
|
+
result = request.send(connection)
|
543
|
+
if result.status == 401 && authorization.respond_to?(:refresh_token)
|
544
|
+
begin
|
545
|
+
authorization.fetch_access_token!
|
546
|
+
result = request.send(connection)
|
547
|
+
rescue Signet::AuthorizationError
|
548
|
+
# Ignore since we want the original error
|
549
|
+
end
|
772
550
|
end
|
551
|
+
|
552
|
+
return result
|
773
553
|
end
|
774
554
|
|
775
555
|
##
|
@@ -796,6 +576,35 @@ module Google
|
|
796
576
|
end
|
797
577
|
return result
|
798
578
|
end
|
579
|
+
|
580
|
+
protected
|
581
|
+
|
582
|
+
##
|
583
|
+
# Resolves a URI template against the client's configured base.
|
584
|
+
#
|
585
|
+
# @api private
|
586
|
+
# @param [String, Addressable::URI, Addressable::Template] template
|
587
|
+
# The template to resolve.
|
588
|
+
# @param [Hash] mapping The mapping that corresponds to the template.
|
589
|
+
# @return [Addressable::URI] The expanded URI.
|
590
|
+
def resolve_uri(template, mapping={})
|
591
|
+
@base_uri ||= Addressable::URI.new(
|
592
|
+
:scheme => 'https',
|
593
|
+
:host => self.host,
|
594
|
+
:port => self.port
|
595
|
+
).normalize
|
596
|
+
template = if template.kind_of?(Addressable::Template)
|
597
|
+
template.pattern
|
598
|
+
elsif template.respond_to?(:to_str)
|
599
|
+
template.to_str
|
600
|
+
else
|
601
|
+
raise TypeError,
|
602
|
+
"Expected String, Addressable::URI, or Addressable::Template, " +
|
603
|
+
"got #{template.class}."
|
604
|
+
end
|
605
|
+
return Addressable::Template.new(@base_uri + template).expand(mapping)
|
606
|
+
end
|
607
|
+
|
799
608
|
end
|
800
609
|
end
|
801
610
|
|