google-api-client 0.4.7 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
- gem 'redcarpet'
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
@@ -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
- # APIClient
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>Author</dt><dd><a href="mailto:bobaman@google.com">Bob Aman</a></dd>
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
  [![Build Status](https://secure.travis-ci.org/google/google-api-ruby-client.png)](http://travis-ci.org/google/google-api-ruby-client)
11
11
  [![Dependency Status](https://gemnasium.com/google/google-api-ruby-client.png)](https://gemnasium.com/google/google-api-ruby-client)
12
12
 
13
- # Description
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
- # Example Usage
18
+ ## Install
19
19
 
20
- # Initialize the client
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
- require 'signet/oauth_1/client'
23
- client = Google::APIClient.new(
24
- :service => 'buzz',
25
- # Buzz has API-specific endpoints
26
- :authorization => Signet::OAuth1::Client.new(
27
- :temporary_credential_uri =>
28
- 'https://www.google.com/accounts/OAuthGetRequestToken',
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
- 'plus.activities.list',
57
- {'collection' => 'public', 'userId' => 'me'}
54
+ :api_method => plus.activities.list,
55
+ :parameters => {'collection' => 'public', 'userId' => 'me'}
58
56
  )
59
57
 
60
- # Install
58
+ puts result.data
61
59
 
62
- Be sure `http://rubygems.org/` is in your gem sources.
60
+ ## API Features
63
61
 
64
- For normal client usage, this is sufficient:
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 = "bobaman@google.com"
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
@@ -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
- request = [method, uri.to_str, headers, [request_body]]
475
- request = client.generate_authenticated_request(:request => request)
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
@@ -1,14 +1,13 @@
1
- gem 'multi_json', '>= 1.0.0'
2
1
  require 'multi_json'
3
2
 
4
- unless MultiJson.respond_to?(:load)
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
- unless MultiJson.respond_to?(:dump)
10
+ if !MultiJson.respond_to?(:dump)
12
11
  module MultiJson
13
12
  class <<self
14
13
  alias :dump :encode
@@ -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.to_s] = value
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["host"] || 'www.googleapis.com'
75
- self.port = options["port"] || 443
76
- self.discovery_path = options["discovery_path"] || '/discovery/v1'
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["application_name"] ? (
82
- "#{options["application_name"]}/" +
83
- "#{options["application_version"] || '0.0.0'}"
78
+ options[:application_name] ? (
79
+ "#{options[:application_name]}/" +
80
+ "#{options[:application_version] || '0.0.0'}"
84
81
  ) : ""
85
82
  )
86
- self.user_agent = options["user_agent"] || (
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?("authorization") ? options["authorization"] : :oauth_2
95
- self.key = options["key"]
96
- self.user_ip = options["user_ip"]
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
- request = self.generate_request(
265
+ response = self.execute!(
297
266
  :http_method => :get,
298
267
  :uri => self.directory_uri,
299
268
  :authenticated => false
300
269
  )
301
- response = self.transmit(:request => request)
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
- request = self.generate_request(
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 = self.transmit(:request => request)
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] rpc_name The API the method is within.
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
- request = self.generate_request(
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
- response = self.transmit(:request => request)
488
- if response.status >= 200 && response.status < 300
489
- @certificates.merge!(
490
- Hash[MultiJson.load(response.body).map do |key, cert|
491
- [key, OpenSSL::X509::Certificate.new(cert)]
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, String] :api_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 [Faraday::Request] The generated request.
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
- # Note: The merge method on a Hash object will coerce an API Reference
545
- # object into a Hash and merge with the default options.
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::BatchRequest, Hash, Array] params
675
- # Either a Google::APIClient::BatchRequest, a Hash, or an Array.
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::BatchRequest, no other parameters are expected.
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, String) api_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 => 'plus.activities.list',
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::BatchRequest) &&
512
+ if params.last.kind_of?(Google::APIClient::Request) &&
712
513
  params.size == 1
713
- batch = params.pop
714
- options = batch.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[:client] = self
764
- options[:connection] ||= Faraday.default_connection
765
- reference = Google::APIClient::Reference.new(options)
766
- request = self.generate_request(reference)
767
- response = self.transmit(
768
- :request => request,
769
- :connection => options[:connection]
770
- )
771
- return Google::APIClient::Result.new(reference, request, response)
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