google-api-client 0.7.0.rc2 → 0.7.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: c9fdb163b06a237193bbfdb00789efa0477f9f25
4
- data.tar.gz: f69ac3dfb9612faee06a4621a68f8cc76cdac706
3
+ metadata.gz: 25f7fed5190421b20ce39568ea716d2a5a52627e
4
+ data.tar.gz: f511d420725a7e69600d7654090d7794743c8591
5
5
  SHA512:
6
- metadata.gz: f26c7cc3ab8beab47c95b2763c8f0c5bc5df4ea04e6daae3ad5f5e9f8c24e3358a295d642ec3c315e269d5a2837ab83fc02122723604fe9c467740b6689e8f0c
7
- data.tar.gz: 1432deab452fc436913508288081f4febf770d995e8dcdbd9ce0f5bf1145e894c4b44ba4a4cf7839e6e48d21d77c80a0c5a90f892ecce341f946118f11072966
6
+ metadata.gz: 4a889315a2b6d96b6d56ac808880203c7dbe6c108a214c610440182e784162a93c753367d49d9cc16b22a50a8d2668e507590d45f6665c3227fe31faed8adf88
7
+ data.tar.gz: 49493d0cb5c148bd88962b1eaca02acba2f21bfc04ef115a6e75958f2677a386a6945698f3ea2054b2f3e635be08fc441441aef149f60aa880503809b7618d90
data/CHANGELOG.md CHANGED
@@ -1,8 +1,11 @@
1
- # 0.7.0.rc2
1
+ # 0.7.0
2
+ * Remove CLI
3
+ * SUpport for automatic retires & backoff. Off by default, enable by setting `retries` on `APIClient`
4
+ * Experimental new interface (see `Google::APIClient::Service`)
2
5
  * Fix warnings when using Faraday separately
3
6
  * Support Google Compute Engine service accounts
4
7
  * Enable gzip compression for responses
5
- * Upgrade to Faraday 0.9.x. Resolves multiple issues with query parameter encodings.
8
+ * Upgrade to Faraday 0.9.0. Resolves multiple issues with query parameter encodings.
6
9
  * Use bundled root certificates for verifying SSL certificates
7
10
  * Rewind media when retrying uploads
8
11
 
data/Gemfile CHANGED
@@ -6,10 +6,11 @@ gem 'signet', '>= 0.5.0'
6
6
  gem 'addressable', '>= 2.3.2'
7
7
  gem 'uuidtools', '>= 2.1.0'
8
8
  gem 'autoparse', '>= 0.3.3'
9
- gem 'faraday', '>= 0.9.0.rc5'
9
+ gem 'faraday', '>= 0.9.0'
10
10
  gem 'multi_json', '>= 1.0.0'
11
11
  gem 'extlib', '>= 0.9.15'
12
12
  gem 'jwt', '~> 0.1.5'
13
+ gem 'retriable', '>= 1.4'
13
14
  gem 'jruby-openssl', :platforms => :jruby
14
15
 
15
16
  group :development do
@@ -18,6 +19,13 @@ group :development do
18
19
  gem 'kramdown'
19
20
  end
20
21
 
22
+
23
+ platforms :rbx do
24
+ gem 'rubysl', '~> 2.0'
25
+ gem 'psych'
26
+ end
27
+
28
+
21
29
  group :examples do
22
30
  gem 'sinatra'
23
31
  end
@@ -29,4 +37,5 @@ group :test, :development do
29
37
  gem 'rcov', '>= 0.9.9', :platform => :mri_18
30
38
  end
31
39
 
40
+
32
41
  gem 'idn', :platform => :mri_18
data/README.md CHANGED
@@ -107,6 +107,16 @@ client.authorization.fetch_access_token!
107
107
  client.execute(...)
108
108
  ```
109
109
 
110
+ Service accounts are also used for delegation in Google Apps domains. The target user for impersonation is specified by setting the `:person` parameter to the user's email address
111
+ in the credentials. Detailed instructions on how to enable delegation for your domain can be found at [developers.google.com](https://developers.google.com/drive/delegation).
112
+
113
+ ### Automatic Retries & Backoff
114
+
115
+ The API client can automatically retry requests for recoverable errors. To enable retries, set the `client.retries` property to
116
+ the number of additional attempts. To avoid flooding servers, retries invovle a 1 second delay that increases on each subsequent retry.
117
+
118
+ The default value for retries is 0, but will be enabled by default in future releases.
119
+
110
120
  ### Batching Requests
111
121
 
112
122
  Some Google APIs support batching requests into a single HTTP request. Use `Google::APIClient::BatchRequest`
@@ -194,7 +204,7 @@ For more information, use `google-api --help`
194
204
 
195
205
  ## Samples
196
206
 
197
- See the full list of [samples on Google Code](http://code.google.com/p/google-api-ruby-client/source/browse?repo=samples).
207
+ See the full list of [samples on Github](https://github.com/google/google-api-ruby-client-samples).
198
208
 
199
209
 
200
210
  ## Support
data/Rakefile CHANGED
@@ -11,7 +11,7 @@ PKG_DISPLAY_NAME = 'Google API Client'
11
11
  PKG_NAME = PKG_DISPLAY_NAME.downcase.gsub(/\s/, '-')
12
12
  PKG_VERSION = Google::APIClient::VERSION::STRING
13
13
  PKG_FILE_NAME = "#{PKG_NAME}-#{PKG_VERSION}"
14
- PKG_HOMEPAGE = 'http://code.google.com/p/google-api-ruby-client/'
14
+ PKG_HOMEPAGE = 'https://github.com/google/google-api-ruby-client'
15
15
 
16
16
  RELEASE_NAME = "REL #{PKG_VERSION}"
17
17
 
@@ -17,6 +17,7 @@ require 'faraday'
17
17
  require 'multi_json'
18
18
  require 'compat/multi_json'
19
19
  require 'stringio'
20
+ require 'retriable'
20
21
 
21
22
  require 'google/api_client/version'
22
23
  require 'google/api_client/logging'
@@ -107,6 +108,7 @@ module Google
107
108
  self.auto_refresh_token = options.fetch(:auto_refresh_token) { true }
108
109
  self.key = options[:key]
109
110
  self.user_ip = options[:user_ip]
111
+ self.retries = options.fetch(:retries) { 0 }
110
112
  @discovery_uris = {}
111
113
  @discovery_documents = {}
112
114
  @discovered_apis = {}
@@ -230,6 +232,13 @@ module Google
230
232
  # The base path. Should almost always be '/discovery/v1'.
231
233
  attr_accessor :discovery_path
232
234
 
235
+ ##
236
+ # Number of times to retry on recoverable errors
237
+ #
238
+ # @return [FixNum]
239
+ # Number of retries
240
+ attr_accessor :retries
241
+
233
242
  ##
234
243
  # Returns the URI for the directory document.
235
244
  #
@@ -424,6 +433,8 @@ module Google
424
433
  # Verifies an ID token against a server certificate. Used to ensure that
425
434
  # an ID token supplied by an untrusted client-side mechanism is valid.
426
435
  # Raises an error if the token is invalid or missing.
436
+ #
437
+ # @deprecated Use the google-id-token gem for verifying JWTs
427
438
  def verify_id_token!
428
439
  require 'jwt'
429
440
  require 'openssl'
@@ -533,6 +544,8 @@ module Google
533
544
  # authenticated, `false` otherwise.
534
545
  # - (TrueClass, FalseClass) :gzip (default: true) -
535
546
  # `true` if gzip enabled, `false` otherwise.
547
+ # - (FixNum) :retries -
548
+ # # of times to retry on recoverable errors
536
549
  #
537
550
  # @return [Google::APIClient::Result] The result from the API, nil if batch.
538
551
  #
@@ -547,7 +560,7 @@ module Google
547
560
  # )
548
561
  #
549
562
  # @see Google::APIClient#generate_request
550
- def execute(*params)
563
+ def execute!(*params)
551
564
  if params.first.kind_of?(Google::APIClient::Request)
552
565
  request = params.shift
553
566
  options = params.shift || {}
@@ -572,53 +585,60 @@ module Google
572
585
 
573
586
  request.headers['User-Agent'] ||= '' + self.user_agent unless self.user_agent.nil?
574
587
  request.headers['Accept-Encoding'] ||= 'gzip' unless options[:gzip] == false
588
+ request.headers['Content-Type'] ||= ''
575
589
  request.parameters['key'] ||= self.key unless self.key.nil?
576
590
  request.parameters['userIp'] ||= self.user_ip unless self.user_ip.nil?
577
591
 
578
592
  connection = options[:connection] || self.connection
579
593
  request.authorization = options[:authorization] || self.authorization unless options[:authenticated] == false
580
-
581
- result = request.send(connection)
582
- if result.status == 401 && request.authorization.respond_to?(:refresh_token) && auto_refresh_token
583
- begin
584
- logger.debug("Attempting refresh of access token & retry of request")
585
- request.authorization.fetch_access_token!
586
- result = request.send(connection, true)
587
- rescue Signet::AuthorizationError
588
- # Ignore since we want the original error
594
+ tries = 1 + (options[:retries] || self.retries)
595
+ Retriable.retriable :tries => tries,
596
+ :on => [TransmissionError],
597
+ :interval => lambda {|attempts| (2 ** attempts) + rand} do
598
+ result = request.send(connection, true)
599
+
600
+ case result.status
601
+ when 200...300
602
+ result
603
+ when 301, 302, 303, 307
604
+ request = generate_request(request.to_hash.merge({
605
+ :uri => result.headers['location'],
606
+ :api_method => nil
607
+ }))
608
+ raise RedirectError.new(result.headers['location'], result)
609
+ when 400...500
610
+ if result.status == 401 && request.authorization.respond_to?(:refresh_token) && auto_refresh_token
611
+ begin
612
+ logger.debug("Attempting refresh of access token & retry of request")
613
+ request.authorization.fetch_access_token!
614
+ rescue Signet::AuthorizationError
615
+ # Ignore since we want the original error
616
+ end
617
+ end
618
+ raise ClientError.new(result.error_message || "A client error has occurred", result)
619
+ when 500...600
620
+ raise ServerError.new(result.error_message || "A server error has occurred", result)
621
+ else
622
+ raise TransmissionError.new(result.error_message || "A transmission error has occurred", result)
589
623
  end
590
624
  end
591
-
592
- return result
593
625
  end
594
626
 
595
627
  ##
596
- # Same as Google::APIClient#execute, but raises an exception if there was
597
- # an error.
628
+ # Same as Google::APIClient#execute!, but does not raise an exception for
629
+ # normal API errros.
598
630
  #
599
631
  # @see Google::APIClient#execute
600
- def execute!(*params)
601
- result = self.execute(*params)
602
- if result.error?
603
- error_message = result.error_message
604
- case result.response.status
605
- when 400...500
606
- exception_type = ClientError
607
- error_message ||= "A client error has occurred."
608
- when 500...600
609
- exception_type = ServerError
610
- error_message ||= "A server error has occurred."
611
- else
612
- exception_type = TransmissionError
613
- error_message ||= "A transmission error has occurred."
614
- end
615
- raise exception_type, error_message
632
+ def execute(*params)
633
+ begin
634
+ return self.execute!(*params)
635
+ rescue TransmissionError => e
636
+ return e.result
616
637
  end
617
- return result
618
638
  end
619
-
639
+
620
640
  protected
621
-
641
+
622
642
  ##
623
643
  # Resolves a URI template against the client's configured base.
624
644
  #
@@ -646,6 +666,7 @@ module Google
646
666
  end
647
667
 
648
668
  end
669
+
649
670
  end
650
671
 
651
672
  require 'google/api_client/version'
@@ -19,6 +19,17 @@ module Google
19
19
  # An error which is raised when there is an unexpected response or other
20
20
  # transport error that prevents an operation from succeeding.
21
21
  class TransmissionError < StandardError
22
+ attr_reader :result
23
+ def initialize(message = nil, result = nil)
24
+ super(message)
25
+ @result = result
26
+ end
27
+ end
28
+
29
+ ##
30
+ # An exception that is raised if a redirect is required
31
+ #
32
+ class RedirectError < TransmissionError
22
33
  end
23
34
 
24
35
  ##
@@ -287,6 +287,7 @@ module Google
287
287
  raise ArgumentError, "Can not specify body & body object for simple uploads"
288
288
  end
289
289
  self.headers['Content-Type'] ||= self.media.content_type
290
+ self.headers['Content-Length'] ||= self.media.length.to_s
290
291
  self.body = self.media
291
292
  when "multipart"
292
293
  unless options[:body_object]
@@ -0,0 +1,233 @@
1
+ # Copyright 2013 Google Inc.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ require 'google/api_client'
16
+ require 'google/api_client/service/stub_generator'
17
+ require 'google/api_client/service/resource'
18
+ require 'google/api_client/service/request'
19
+ require 'google/api_client/service/result'
20
+ require 'google/api_client/service/batch'
21
+ require 'google/api_client/service/simple_file_store'
22
+
23
+ module Google
24
+ class APIClient
25
+
26
+ ##
27
+ # Experimental new programming interface at the API level.
28
+ # Hides Google::APIClient. Designed to be easier to use, with less code.
29
+ #
30
+ # @example
31
+ # calendar = Google::APIClient::Service.new('calendar', 'v3')
32
+ # result = calendar.events.list('calendarId' => 'primary').execute()
33
+ class Service
34
+ include Google::APIClient::Service::StubGenerator
35
+ extend Forwardable
36
+
37
+ DEFAULT_CACHE_FILE = 'discovery.cache'
38
+
39
+ # Cache for discovered APIs.
40
+ @@discovered = {}
41
+
42
+ ##
43
+ # Creates a new Service.
44
+ #
45
+ # @param [String, Symbol] api_name
46
+ # The name of the API this service will access.
47
+ # @param [String, Symbol] api_version
48
+ # The version of the API this service will access.
49
+ # @param [Hash] options
50
+ # The configuration parameters for the service.
51
+ # @option options [Symbol, #generate_authenticated_request] :authorization
52
+ # (:oauth_1)
53
+ # The authorization mechanism used by the client. The following
54
+ # mechanisms are supported out-of-the-box:
55
+ # <ul>
56
+ # <li><code>:two_legged_oauth_1</code></li>
57
+ # <li><code>:oauth_1</code></li>
58
+ # <li><code>:oauth_2</code></li>
59
+ # </ul>
60
+ # @option options [Boolean] :auto_refresh_token (true)
61
+ # The setting that controls whether or not the api client attempts to
62
+ # refresh authorization when a 401 is hit in #execute. If the token does
63
+ # not support it, this option is ignored.
64
+ # @option options [String] :application_name
65
+ # The name of the application using the client.
66
+ # @option options [String] :application_version
67
+ # The version number of the application using the client.
68
+ # @option options [String] :host ("www.googleapis.com")
69
+ # The API hostname used by the client. This rarely needs to be changed.
70
+ # @option options [String] :port (443)
71
+ # The port number used by the client. This rarely needs to be changed.
72
+ # @option options [String] :discovery_path ("/discovery/v1")
73
+ # The discovery base path. This rarely needs to be changed.
74
+ # @option options [String] :ca_file
75
+ # Optional set of root certificates to use when validating SSL connections.
76
+ # By default, a bundled set of trusted roots will be used.
77
+ # @option options [#generate_authenticated_request] :authorization
78
+ # The authorization mechanism for requests. Used only if
79
+ # `:authenticated` is `true`.
80
+ # @option options [TrueClass, FalseClass] :authenticated (default: true)
81
+ # `true` if requests must be signed or somehow
82
+ # authenticated, `false` otherwise.
83
+ # @option options [TrueClass, FalseClass] :gzip (default: true)
84
+ # `true` if gzip enabled, `false` otherwise.
85
+ # @option options [Faraday::Connection] :connection
86
+ # A custom connection to be used for all requests.
87
+ # @option options [ActiveSupport::Cache::Store, :default] :discovery_cache
88
+ # A cache store to place the discovery documents for loaded APIs.
89
+ # Avoids unnecessary roundtrips to the discovery service.
90
+ # :default loads the default local file cache store.
91
+ def initialize(api_name, api_version, options = {})
92
+ @api_name = api_name.to_s
93
+ if api_version.nil?
94
+ raise ArgumentError,
95
+ "API version must be set"
96
+ end
97
+ @api_version = api_version.to_s
98
+ if options && !options.respond_to?(:to_hash)
99
+ raise ArgumentError,
100
+ "expected options Hash, got #{options.class}"
101
+ end
102
+
103
+ params = {}
104
+ [:application_name, :application_version, :authorization, :host, :port,
105
+ :discovery_path, :auto_refresh_token, :key, :user_ip,
106
+ :ca_file].each do |option|
107
+ if options.include? option
108
+ params[option] = options[option]
109
+ end
110
+ end
111
+
112
+ @client = Google::APIClient.new(params)
113
+
114
+ @connection = options[:connection] || @client.connection
115
+
116
+ @options = options
117
+
118
+ # Initialize cache store. Default to SimpleFileStore if :cache_store
119
+ # is not provided and we have write permissions.
120
+ if options.include? :cache_store
121
+ @cache_store = options[:cache_store]
122
+ else
123
+ cache_exists = File.exist?(DEFAULT_CACHE_FILE)
124
+ if (cache_exists && File.writable?(DEFAULT_CACHE_FILE)) ||
125
+ (!cache_exists && File.writable?(Dir.pwd))
126
+ @cache_store = Google::APIClient::Service::SimpleFileStore.new(
127
+ DEFAULT_CACHE_FILE)
128
+ end
129
+ end
130
+
131
+ # Attempt to read API definition from memory cache.
132
+ # Not thread-safe, but the worst that can happen is a cache miss.
133
+ unless @api = @@discovered[[api_name, api_version]]
134
+ # Attempt to read API definition from cache store, if there is one.
135
+ # If there's a miss or no cache store, call discovery service.
136
+ if !@cache_store.nil?
137
+ @api = @cache_store.fetch("%s/%s" % [api_name, api_version]) do
138
+ @client.discovered_api(api_name, api_version)
139
+ end
140
+ else
141
+ @api = @client.discovered_api(api_name, api_version)
142
+ end
143
+ @@discovered[[api_name, api_version]] = @api
144
+ end
145
+
146
+ generate_call_stubs(self, @api)
147
+ end
148
+
149
+ ##
150
+ # Returns the authorization mechanism used by the service.
151
+ #
152
+ # @return [#generate_authenticated_request] The authorization mechanism.
153
+ def_delegators :@client, :authorization, :authorization=
154
+
155
+ ##
156
+ # The setting that controls whether or not the service attempts to
157
+ # refresh authorization when a 401 is hit during an API call.
158
+ #
159
+ # @return [Boolean]
160
+ def_delegators :@client, :auto_refresh_token, :auto_refresh_token=
161
+
162
+ ##
163
+ # The application's API key issued by the API console.
164
+ #
165
+ # @return [String] The API key.
166
+ def_delegators :@client, :key, :key=
167
+
168
+ ##
169
+ # The Faraday/HTTP connection used by this service.
170
+ #
171
+ # @return [Faraday::Connection]
172
+ attr_accessor :connection
173
+
174
+ ##
175
+ # The cache store used for storing discovery documents.
176
+ #
177
+ # @return [ActiveSupport::Cache::Store,
178
+ # Google::APIClient::Service::SimpleFileStore,
179
+ # nil]
180
+ attr_reader :cache_store
181
+
182
+ ##
183
+ # Prepares a Google::APIClient::BatchRequest object to make batched calls.
184
+ # @param [Array] calls
185
+ # Optional array of Google::APIClient::Service::Request to initialize
186
+ # the batch request with.
187
+ # @param [Proc] block
188
+ # Callback for every call's response. Won't be called if a call defined
189
+ # a callback of its own.
190
+ #
191
+ # @yield [Google::APIClient::Service::Result]
192
+ # block to be called when result ready
193
+ def batch(calls = nil, &block)
194
+ Google::APIClient::Service::BatchRequest.new(self, calls, &block)
195
+ end
196
+
197
+ ##
198
+ # Executes an API request.
199
+ # Do not call directly; this method is only used by Request objects when
200
+ # executing.
201
+ #
202
+ # @param [Google::APIClient::Service::Request,
203
+ # Google::APIClient::Service::BatchCall] request
204
+ # The request to be executed.
205
+ def execute(request)
206
+ if request.instance_of? Google::APIClient::Service::Request
207
+ params = {:api_method => request.method,
208
+ :parameters => request.parameters,
209
+ :connection => @connection}
210
+ if request.respond_to? :body
211
+ if request.body.respond_to? :to_hash
212
+ params[:body_object] = request.body
213
+ else
214
+ params[:body] = request.body
215
+ end
216
+ end
217
+ if request.respond_to? :media
218
+ params[:media] = request.media
219
+ end
220
+ [:authenticated, :gzip].each do |option|
221
+ if @options.include? option
222
+ params[option] = @options[option]
223
+ end
224
+ end
225
+ result = @client.execute(params)
226
+ return Google::APIClient::Service::Result.new(request, result)
227
+ elsif request.instance_of? Google::APIClient::Service::BatchRequest
228
+ @client.execute(request.base_batch)
229
+ end
230
+ end
231
+ end
232
+ end
233
+ end