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.
@@ -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