cure-google-api-client 0.8.7.1
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 +7 -0
- data/CHANGELOG.md +178 -0
- data/Gemfile +9 -0
- data/LICENSE +202 -0
- data/README.md +218 -0
- data/Rakefile +41 -0
- data/google-api-client.gemspec +43 -0
- data/lib/cacerts.pem +2183 -0
- data/lib/compat/multi_json.rb +19 -0
- data/lib/google/api_client.rb +750 -0
- data/lib/google/api_client/auth/compute_service_account.rb +28 -0
- data/lib/google/api_client/auth/file_storage.rb +59 -0
- data/lib/google/api_client/auth/installed_app.rb +126 -0
- data/lib/google/api_client/auth/jwt_asserter.rb +126 -0
- data/lib/google/api_client/auth/key_utils.rb +93 -0
- data/lib/google/api_client/auth/pkcs12.rb +41 -0
- data/lib/google/api_client/auth/storage.rb +102 -0
- data/lib/google/api_client/auth/storages/file_store.rb +58 -0
- data/lib/google/api_client/auth/storages/redis_store.rb +54 -0
- data/lib/google/api_client/batch.rb +326 -0
- data/lib/google/api_client/charset.rb +33 -0
- data/lib/google/api_client/client_secrets.rb +179 -0
- data/lib/google/api_client/discovery.rb +19 -0
- data/lib/google/api_client/discovery/api.rb +310 -0
- data/lib/google/api_client/discovery/media.rb +77 -0
- data/lib/google/api_client/discovery/method.rb +363 -0
- data/lib/google/api_client/discovery/resource.rb +156 -0
- data/lib/google/api_client/discovery/schema.rb +117 -0
- data/lib/google/api_client/environment.rb +42 -0
- data/lib/google/api_client/errors.rb +65 -0
- data/lib/google/api_client/gzip.rb +28 -0
- data/lib/google/api_client/logging.rb +32 -0
- data/lib/google/api_client/media.rb +259 -0
- data/lib/google/api_client/railtie.rb +18 -0
- data/lib/google/api_client/reference.rb +27 -0
- data/lib/google/api_client/request.rb +350 -0
- data/lib/google/api_client/result.rb +255 -0
- data/lib/google/api_client/service.rb +233 -0
- data/lib/google/api_client/service/batch.rb +110 -0
- data/lib/google/api_client/service/request.rb +144 -0
- data/lib/google/api_client/service/resource.rb +40 -0
- data/lib/google/api_client/service/result.rb +162 -0
- data/lib/google/api_client/service/simple_file_store.rb +151 -0
- data/lib/google/api_client/service/stub_generator.rb +61 -0
- data/lib/google/api_client/service_account.rb +21 -0
- data/lib/google/api_client/version.rb +26 -0
- data/spec/google/api_client/auth/storage_spec.rb +122 -0
- data/spec/google/api_client/auth/storages/file_store_spec.rb +40 -0
- data/spec/google/api_client/auth/storages/redis_store_spec.rb +70 -0
- data/spec/google/api_client/batch_spec.rb +248 -0
- data/spec/google/api_client/client_secrets_spec.rb +53 -0
- data/spec/google/api_client/discovery_spec.rb +708 -0
- data/spec/google/api_client/gzip_spec.rb +98 -0
- data/spec/google/api_client/media_spec.rb +178 -0
- data/spec/google/api_client/request_spec.rb +29 -0
- data/spec/google/api_client/result_spec.rb +207 -0
- data/spec/google/api_client/service_account_spec.rb +169 -0
- data/spec/google/api_client/service_spec.rb +618 -0
- data/spec/google/api_client/simple_file_store_spec.rb +133 -0
- data/spec/google/api_client_spec.rb +352 -0
- data/spec/spec_helper.rb +66 -0
- metadata +339 -0
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'rails/railtie'
|
2
|
+
require 'google/api_client/logging'
|
3
|
+
|
4
|
+
module Google
|
5
|
+
class APIClient
|
6
|
+
|
7
|
+
##
|
8
|
+
# Optional support class for Rails. Currently replaces the built-in logger
|
9
|
+
# with Rails' application log.
|
10
|
+
#
|
11
|
+
class Railtie < Rails::Railtie
|
12
|
+
initializer 'google-api-client' do |app|
|
13
|
+
logger = app.config.logger || Rails.logger
|
14
|
+
Google::APIClient.logger = logger unless logger.nil?
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# Copyright 2010 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/request'
|
16
|
+
|
17
|
+
module Google
|
18
|
+
class APIClient
|
19
|
+
##
|
20
|
+
# Subclass of Request for backwards compatibility with pre-0.5.0 versions of the library
|
21
|
+
#
|
22
|
+
# @deprecated
|
23
|
+
# use {Google::APIClient::Request} instead
|
24
|
+
class Reference < Request
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,350 @@
|
|
1
|
+
# Copyright 2010 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 'faraday'
|
16
|
+
require 'faraday/request/multipart'
|
17
|
+
require 'compat/multi_json'
|
18
|
+
require 'addressable/uri'
|
19
|
+
require 'stringio'
|
20
|
+
require 'google/api_client/discovery'
|
21
|
+
require 'google/api_client/logging'
|
22
|
+
|
23
|
+
module Google
|
24
|
+
class APIClient
|
25
|
+
|
26
|
+
##
|
27
|
+
# Represents an API request.
|
28
|
+
class Request
|
29
|
+
include Google::APIClient::Logging
|
30
|
+
|
31
|
+
MULTIPART_BOUNDARY = "-----------RubyApiMultipartPost".freeze
|
32
|
+
|
33
|
+
# @return [Hash] Request parameters
|
34
|
+
attr_reader :parameters
|
35
|
+
# @return [Hash] Additional HTTP headers
|
36
|
+
attr_reader :headers
|
37
|
+
# @return [Google::APIClient::Method] API method to invoke
|
38
|
+
attr_reader :api_method
|
39
|
+
# @return [Google::APIClient::UploadIO] File to upload
|
40
|
+
attr_accessor :media
|
41
|
+
# @return [#generated_authenticated_request] User credentials
|
42
|
+
attr_accessor :authorization
|
43
|
+
# @return [TrueClass,FalseClass] True if request should include credentials
|
44
|
+
attr_accessor :authenticated
|
45
|
+
# @return [#read, #to_str] Request body
|
46
|
+
attr_accessor :body
|
47
|
+
|
48
|
+
##
|
49
|
+
# Build a request
|
50
|
+
#
|
51
|
+
# @param [Hash] options
|
52
|
+
# @option options [Hash, Array] :parameters
|
53
|
+
# Request parameters for the API method.
|
54
|
+
# @option options [Google::APIClient::Method] :api_method
|
55
|
+
# API method to invoke. Either :api_method or :uri must be specified
|
56
|
+
# @option options [TrueClass, FalseClass] :authenticated
|
57
|
+
# True if request should include credentials. Implicitly true if
|
58
|
+
# unspecified and :authorization present
|
59
|
+
# @option options [#generate_signed_request] :authorization
|
60
|
+
# OAuth credentials
|
61
|
+
# @option options [Google::APIClient::UploadIO] :media
|
62
|
+
# File to upload, if media upload request
|
63
|
+
# @option options [#to_json, #to_hash] :body_object
|
64
|
+
# Main body of the API request. Typically hash or object that can
|
65
|
+
# be serialized to JSON
|
66
|
+
# @option options [#read, #to_str] :body
|
67
|
+
# Raw body to send in POST/PUT requests
|
68
|
+
# @option options [String, Addressable::URI] :uri
|
69
|
+
# URI to request. Either :api_method or :uri must be specified
|
70
|
+
# @option options [String, Symbol] :http_method
|
71
|
+
# HTTP method when requesting a URI
|
72
|
+
def initialize(options={})
|
73
|
+
@parameters = Faraday::Utils::ParamsHash.new
|
74
|
+
@headers = Faraday::Utils::Headers.new
|
75
|
+
|
76
|
+
self.parameters.merge!(options[:parameters]) unless options[:parameters].nil?
|
77
|
+
self.headers.merge!(options[:headers]) unless options[:headers].nil?
|
78
|
+
self.api_method = options[:api_method]
|
79
|
+
self.authenticated = options[:authenticated]
|
80
|
+
self.authorization = options[:authorization]
|
81
|
+
|
82
|
+
# These parameters are handled differently because they're not
|
83
|
+
# parameters to the API method, but rather to the API system.
|
84
|
+
self.parameters['key'] ||= options[:key] if options[:key]
|
85
|
+
self.parameters['userIp'] ||= options[:user_ip] if options[:user_ip]
|
86
|
+
|
87
|
+
if options[:media]
|
88
|
+
self.initialize_media_upload(options)
|
89
|
+
elsif options[:body]
|
90
|
+
self.body = options[:body]
|
91
|
+
elsif options[:body_object]
|
92
|
+
self.headers['Content-Type'] ||= 'application/json'
|
93
|
+
self.body = serialize_body(options[:body_object])
|
94
|
+
else
|
95
|
+
self.body = ''
|
96
|
+
end
|
97
|
+
|
98
|
+
unless self.api_method
|
99
|
+
self.http_method = options[:http_method] || 'GET'
|
100
|
+
self.uri = options[:uri]
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
# @!attribute [r] upload_type
|
105
|
+
# @return [String] protocol used for upload
|
106
|
+
def upload_type
|
107
|
+
return self.parameters['uploadType'] || self.parameters['upload_type']
|
108
|
+
end
|
109
|
+
|
110
|
+
# @!attribute http_method
|
111
|
+
# @return [Symbol] HTTP method if invoking a URI
|
112
|
+
def http_method
|
113
|
+
return @http_method ||= self.api_method.http_method.to_s.downcase.to_sym
|
114
|
+
end
|
115
|
+
|
116
|
+
def http_method=(new_http_method)
|
117
|
+
if new_http_method.kind_of?(Symbol)
|
118
|
+
@http_method = new_http_method.to_s.downcase.to_sym
|
119
|
+
elsif new_http_method.respond_to?(:to_str)
|
120
|
+
@http_method = new_http_method.to_s.downcase.to_sym
|
121
|
+
else
|
122
|
+
raise TypeError,
|
123
|
+
"Expected String or Symbol, got #{new_http_method.class}."
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
def api_method=(new_api_method)
|
128
|
+
if new_api_method.nil? || new_api_method.kind_of?(Google::APIClient::Method)
|
129
|
+
@api_method = new_api_method
|
130
|
+
else
|
131
|
+
raise TypeError,
|
132
|
+
"Expected Google::APIClient::Method, got #{new_api_method.class}."
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
# @!attribute uri
|
137
|
+
# @return [Addressable::URI] URI to send request
|
138
|
+
def uri
|
139
|
+
return @uri ||= self.api_method.generate_uri(self.parameters)
|
140
|
+
end
|
141
|
+
|
142
|
+
def uri=(new_uri)
|
143
|
+
@uri = Addressable::URI.parse(new_uri)
|
144
|
+
@parameters.update(@uri.query_values) unless @uri.query_values.nil?
|
145
|
+
end
|
146
|
+
|
147
|
+
|
148
|
+
# Transmits the request with the given connection
|
149
|
+
#
|
150
|
+
# @api private
|
151
|
+
#
|
152
|
+
# @param [Faraday::Connection] connection
|
153
|
+
# the connection to transmit with
|
154
|
+
# @param [TrueValue,FalseValue] is_retry
|
155
|
+
# True if request has been previous sent
|
156
|
+
#
|
157
|
+
# @return [Google::APIClient::Result]
|
158
|
+
# result of API request
|
159
|
+
def send(connection, is_retry = false)
|
160
|
+
self.body.rewind if is_retry && self.body.respond_to?(:rewind)
|
161
|
+
env = self.to_env(connection)
|
162
|
+
logger.debug { "#{self.class} Sending API request #{env[:method]} #{env[:url].to_s} #{env[:request_headers]}" }
|
163
|
+
http_response = connection.app.call(env)
|
164
|
+
result = self.process_http_response(http_response)
|
165
|
+
|
166
|
+
logger.debug { "#{self.class} Result: #{result.status} #{result.headers}" }
|
167
|
+
|
168
|
+
# Resumamble slightly different than other upload protocols in that it requires at least
|
169
|
+
# 2 requests.
|
170
|
+
if result.status == 200 && self.upload_type == 'resumable' && self.media
|
171
|
+
upload = result.resumable_upload
|
172
|
+
unless upload.complete?
|
173
|
+
logger.debug { "#{self.class} Sending upload body" }
|
174
|
+
result = upload.send(connection)
|
175
|
+
end
|
176
|
+
end
|
177
|
+
return result
|
178
|
+
end
|
179
|
+
|
180
|
+
# Convert to an HTTP request. Returns components in order of method, URI,
|
181
|
+
# request headers, and body
|
182
|
+
#
|
183
|
+
# @api private
|
184
|
+
#
|
185
|
+
# @return [Array<(Symbol, Addressable::URI, Hash, [#read,#to_str])>]
|
186
|
+
def to_http_request
|
187
|
+
request = (
|
188
|
+
if self.api_method
|
189
|
+
self.api_method.generate_request(self.parameters, self.body, self.headers)
|
190
|
+
elsif self.uri
|
191
|
+
unless self.parameters.empty?
|
192
|
+
self.uri.query = Addressable::URI.form_encode(self.parameters)
|
193
|
+
end
|
194
|
+
[self.http_method, self.uri.to_s, self.headers, self.body]
|
195
|
+
end)
|
196
|
+
return request
|
197
|
+
end
|
198
|
+
|
199
|
+
##
|
200
|
+
# Hashified verison of the API request
|
201
|
+
#
|
202
|
+
# @return [Hash]
|
203
|
+
def to_hash
|
204
|
+
options = {}
|
205
|
+
if self.api_method
|
206
|
+
options[:api_method] = self.api_method
|
207
|
+
options[:parameters] = self.parameters
|
208
|
+
else
|
209
|
+
options[:http_method] = self.http_method
|
210
|
+
options[:uri] = self.uri
|
211
|
+
end
|
212
|
+
options[:headers] = self.headers
|
213
|
+
options[:body] = self.body
|
214
|
+
options[:media] = self.media
|
215
|
+
unless self.authorization.nil?
|
216
|
+
options[:authorization] = self.authorization
|
217
|
+
end
|
218
|
+
return options
|
219
|
+
end
|
220
|
+
|
221
|
+
##
|
222
|
+
# Prepares the request for execution, building a hash of parts
|
223
|
+
# suitable for sending to Faraday::Connection.
|
224
|
+
#
|
225
|
+
# @api private
|
226
|
+
#
|
227
|
+
# @param [Faraday::Connection] connection
|
228
|
+
# Connection for building the request
|
229
|
+
#
|
230
|
+
# @return [Hash]
|
231
|
+
# Encoded request
|
232
|
+
def to_env(connection)
|
233
|
+
method, uri, headers, body = self.to_http_request
|
234
|
+
http_request = connection.build_request(method) do |req|
|
235
|
+
req.url(uri.to_s)
|
236
|
+
req.headers.update(headers)
|
237
|
+
req.body = body
|
238
|
+
end
|
239
|
+
|
240
|
+
if self.authorization.respond_to?(:generate_authenticated_request)
|
241
|
+
http_request = self.authorization.generate_authenticated_request(
|
242
|
+
:request => http_request,
|
243
|
+
:connection => connection
|
244
|
+
)
|
245
|
+
end
|
246
|
+
|
247
|
+
http_request.to_env(connection)
|
248
|
+
end
|
249
|
+
|
250
|
+
##
|
251
|
+
# Convert HTTP response to an API Result
|
252
|
+
#
|
253
|
+
# @api private
|
254
|
+
#
|
255
|
+
# @param [Faraday::Response] response
|
256
|
+
# HTTP response
|
257
|
+
#
|
258
|
+
# @return [Google::APIClient::Result]
|
259
|
+
# Processed API response
|
260
|
+
def process_http_response(response)
|
261
|
+
Result.new(self, response)
|
262
|
+
end
|
263
|
+
|
264
|
+
protected
|
265
|
+
|
266
|
+
##
|
267
|
+
# Adjust headers & body for media uploads
|
268
|
+
#
|
269
|
+
# @api private
|
270
|
+
#
|
271
|
+
# @param [Hash] options
|
272
|
+
# @option options [Hash, Array] :parameters
|
273
|
+
# Request parameters for the API method.
|
274
|
+
# @option options [Google::APIClient::UploadIO] :media
|
275
|
+
# File to upload, if media upload request
|
276
|
+
# @option options [#to_json, #to_hash] :body_object
|
277
|
+
# Main body of the API request. Typically hash or object that can
|
278
|
+
# be serialized to JSON
|
279
|
+
# @option options [#read, #to_str] :body
|
280
|
+
# Raw body to send in POST/PUT requests
|
281
|
+
def initialize_media_upload(options)
|
282
|
+
self.media = options[:media]
|
283
|
+
case self.upload_type
|
284
|
+
when "media"
|
285
|
+
if options[:body] || options[:body_object]
|
286
|
+
raise ArgumentError, "Can not specify body & body object for simple uploads"
|
287
|
+
end
|
288
|
+
self.headers['Content-Type'] ||= self.media.content_type
|
289
|
+
self.headers['Content-Length'] ||= self.media.length.to_s
|
290
|
+
self.body = self.media
|
291
|
+
when "multipart"
|
292
|
+
unless options[:body_object]
|
293
|
+
raise ArgumentError, "Multipart requested but no body object"
|
294
|
+
end
|
295
|
+
metadata = StringIO.new(serialize_body(options[:body_object]))
|
296
|
+
build_multipart([Faraday::UploadIO.new(metadata, 'application/json', 'file.json'), self.media])
|
297
|
+
when "resumable"
|
298
|
+
file_length = self.media.length
|
299
|
+
self.headers['X-Upload-Content-Type'] = self.media.content_type
|
300
|
+
self.headers['X-Upload-Content-Length'] = file_length.to_s
|
301
|
+
if options[:body_object]
|
302
|
+
self.headers['Content-Type'] ||= 'application/json'
|
303
|
+
self.body = serialize_body(options[:body_object])
|
304
|
+
else
|
305
|
+
self.body = ''
|
306
|
+
end
|
307
|
+
end
|
308
|
+
end
|
309
|
+
|
310
|
+
##
|
311
|
+
# Assemble a multipart message from a set of parts
|
312
|
+
#
|
313
|
+
# @api private
|
314
|
+
#
|
315
|
+
# @param [Array<[#read,#to_str]>] parts
|
316
|
+
# Array of parts to encode.
|
317
|
+
# @param [String] mime_type
|
318
|
+
# MIME type of the message
|
319
|
+
# @param [String] boundary
|
320
|
+
# Boundary for separating each part of the message
|
321
|
+
def build_multipart(parts, mime_type = 'multipart/related', boundary = MULTIPART_BOUNDARY)
|
322
|
+
env = Faraday::Env.new
|
323
|
+
env.request = Faraday::RequestOptions.new
|
324
|
+
env.request.boundary = boundary
|
325
|
+
env.request_headers = {'Content-Type' => "#{mime_type};boundary=#{boundary}"}
|
326
|
+
multipart = Faraday::Request::Multipart.new
|
327
|
+
self.body = multipart.create_multipart(env, parts.map {|part| [nil, part]})
|
328
|
+
self.headers.update(env[:request_headers])
|
329
|
+
end
|
330
|
+
|
331
|
+
##
|
332
|
+
# Serialize body object to JSON
|
333
|
+
#
|
334
|
+
# @api private
|
335
|
+
#
|
336
|
+
# @param [#to_json,#to_hash] body
|
337
|
+
# object to serialize
|
338
|
+
#
|
339
|
+
# @return [String]
|
340
|
+
# JSON
|
341
|
+
def serialize_body(body)
|
342
|
+
return body.to_json if body.respond_to?(:to_json)
|
343
|
+
return MultiJson.dump(body.to_hash) if body.respond_to?(:to_hash)
|
344
|
+
raise TypeError, 'Could not convert body object to JSON.' +
|
345
|
+
'Must respond to :to_json or :to_hash.'
|
346
|
+
end
|
347
|
+
|
348
|
+
end
|
349
|
+
end
|
350
|
+
end
|
@@ -0,0 +1,255 @@
|
|
1
|
+
# Copyright 2010 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
|
+
|
16
|
+
module Google
|
17
|
+
class APIClient
|
18
|
+
##
|
19
|
+
# This class wraps a result returned by an API call.
|
20
|
+
class Result
|
21
|
+
extend Forwardable
|
22
|
+
|
23
|
+
##
|
24
|
+
# Init the result
|
25
|
+
#
|
26
|
+
# @param [Google::APIClient::Request] request
|
27
|
+
# The original request
|
28
|
+
# @param [Faraday::Response] response
|
29
|
+
# Raw HTTP Response
|
30
|
+
def initialize(request, response)
|
31
|
+
@request = request
|
32
|
+
@response = response
|
33
|
+
@media_upload = reference if reference.kind_of?(ResumableUpload)
|
34
|
+
end
|
35
|
+
|
36
|
+
# @return [Google::APIClient::Request] Original request object
|
37
|
+
attr_reader :request
|
38
|
+
# @return [Faraday::Response] HTTP response
|
39
|
+
attr_reader :response
|
40
|
+
# @!attribute [r] reference
|
41
|
+
# @return [Google::APIClient::Request] Original request object
|
42
|
+
# @deprecated See {#request}
|
43
|
+
alias_method :reference, :request # For compatibility with pre-beta clients
|
44
|
+
|
45
|
+
# @!attribute [r] status
|
46
|
+
# @return [Fixnum] HTTP status code
|
47
|
+
# @!attribute [r] headers
|
48
|
+
# @return [Hash] HTTP response headers
|
49
|
+
# @!attribute [r] body
|
50
|
+
# @return [String] HTTP response body
|
51
|
+
def_delegators :@response, :status, :headers, :body
|
52
|
+
|
53
|
+
# @!attribute [r] resumable_upload
|
54
|
+
# @return [Google::APIClient::ResumableUpload] For resuming media uploads
|
55
|
+
def resumable_upload
|
56
|
+
@media_upload ||= (
|
57
|
+
options = self.reference.to_hash.merge(
|
58
|
+
:uri => self.headers['location'],
|
59
|
+
:media => self.reference.media
|
60
|
+
)
|
61
|
+
Google::APIClient::ResumableUpload.new(options)
|
62
|
+
)
|
63
|
+
end
|
64
|
+
|
65
|
+
##
|
66
|
+
# Get the content type of the response
|
67
|
+
# @!attribute [r] media_type
|
68
|
+
# @return [String]
|
69
|
+
# Value of content-type header
|
70
|
+
def media_type
|
71
|
+
_, content_type = self.headers.detect do |h, v|
|
72
|
+
h.downcase == 'Content-Type'.downcase
|
73
|
+
end
|
74
|
+
if content_type
|
75
|
+
return content_type[/^([^;]*);?.*$/, 1].strip.downcase
|
76
|
+
else
|
77
|
+
return nil
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
##
|
82
|
+
# Check if request failed
|
83
|
+
#
|
84
|
+
# @!attribute [r] error?
|
85
|
+
# @return [TrueClass, FalseClass]
|
86
|
+
# true if result of operation is an error
|
87
|
+
def error?
|
88
|
+
return self.response.status >= 400
|
89
|
+
end
|
90
|
+
|
91
|
+
##
|
92
|
+
# Check if request was successful
|
93
|
+
#
|
94
|
+
# @!attribute [r] success?
|
95
|
+
# @return [TrueClass, FalseClass]
|
96
|
+
# true if result of operation was successful
|
97
|
+
def success?
|
98
|
+
return !self.error?
|
99
|
+
end
|
100
|
+
|
101
|
+
##
|
102
|
+
# Extracts error messages from the response body
|
103
|
+
#
|
104
|
+
# @!attribute [r] error_message
|
105
|
+
# @return [String]
|
106
|
+
# error message, if available
|
107
|
+
def error_message
|
108
|
+
if self.data?
|
109
|
+
if self.data.respond_to?(:error) &&
|
110
|
+
self.data.error.respond_to?(:message)
|
111
|
+
# You're going to get a terrible error message if the response isn't
|
112
|
+
# parsed successfully as an error.
|
113
|
+
return self.data.error.message
|
114
|
+
elsif self.data['error'] && self.data['error']['message']
|
115
|
+
return self.data['error']['message']
|
116
|
+
end
|
117
|
+
end
|
118
|
+
return self.body
|
119
|
+
end
|
120
|
+
|
121
|
+
##
|
122
|
+
# Check for parsable data in response
|
123
|
+
#
|
124
|
+
# @!attribute [r] data?
|
125
|
+
# @return [TrueClass, FalseClass]
|
126
|
+
# true if body can be parsed
|
127
|
+
def data?
|
128
|
+
!(self.body.nil? || self.body.empty? || self.media_type != 'application/json')
|
129
|
+
end
|
130
|
+
|
131
|
+
##
|
132
|
+
# Return parsed version of the response body.
|
133
|
+
#
|
134
|
+
# @!attribute [r] data
|
135
|
+
# @return [Object, Hash, String]
|
136
|
+
# Object if body parsable from API schema, Hash if JSON, raw body if unable to parse
|
137
|
+
def data
|
138
|
+
return @data ||= (begin
|
139
|
+
if self.data?
|
140
|
+
media_type = self.media_type
|
141
|
+
data = self.body
|
142
|
+
case media_type
|
143
|
+
when 'application/json'
|
144
|
+
data = MultiJson.load(data)
|
145
|
+
# Strip data wrapper, if present
|
146
|
+
data = data['data'] if data.has_key?('data')
|
147
|
+
else
|
148
|
+
raise ArgumentError,
|
149
|
+
"Content-Type not supported for parsing: #{media_type}"
|
150
|
+
end
|
151
|
+
if @request.api_method && @request.api_method.response_schema
|
152
|
+
# Automatically parse using the schema designated for the
|
153
|
+
# response of this API method.
|
154
|
+
data = @request.api_method.response_schema.new(data)
|
155
|
+
data
|
156
|
+
else
|
157
|
+
# Otherwise, return the raw unparsed value.
|
158
|
+
# This value must be indexable like a Hash.
|
159
|
+
data
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end)
|
163
|
+
end
|
164
|
+
|
165
|
+
##
|
166
|
+
# Get the token used for requesting the next page of data
|
167
|
+
#
|
168
|
+
# @!attribute [r] next_page_token
|
169
|
+
# @return [String]
|
170
|
+
# next page token
|
171
|
+
def next_page_token
|
172
|
+
if self.data.respond_to?(:next_page_token)
|
173
|
+
return self.data.next_page_token
|
174
|
+
elsif self.data.respond_to?(:[])
|
175
|
+
return self.data["nextPageToken"]
|
176
|
+
else
|
177
|
+
raise TypeError, "Data object did not respond to #next_page_token."
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
##
|
182
|
+
# Build a request for fetching the next page of data
|
183
|
+
#
|
184
|
+
# @return [Google::APIClient::Request]
|
185
|
+
# API request for retrieving next page, nil if no page token available
|
186
|
+
def next_page
|
187
|
+
return nil unless self.next_page_token
|
188
|
+
merged_parameters = Hash[self.reference.parameters].merge({
|
189
|
+
self.page_token_param => self.next_page_token
|
190
|
+
})
|
191
|
+
# Because Requests can be coerced to Hashes, we can merge them,
|
192
|
+
# preserving all context except the API method parameters that we're
|
193
|
+
# using for pagination.
|
194
|
+
return Google::APIClient::Request.new(
|
195
|
+
Hash[self.reference].merge(:parameters => merged_parameters)
|
196
|
+
)
|
197
|
+
end
|
198
|
+
|
199
|
+
##
|
200
|
+
# Get the token used for requesting the previous page of data
|
201
|
+
#
|
202
|
+
# @!attribute [r] prev_page_token
|
203
|
+
# @return [String]
|
204
|
+
# previous page token
|
205
|
+
def prev_page_token
|
206
|
+
if self.data.respond_to?(:prev_page_token)
|
207
|
+
return self.data.prev_page_token
|
208
|
+
elsif self.data.respond_to?(:[])
|
209
|
+
return self.data["prevPageToken"]
|
210
|
+
else
|
211
|
+
raise TypeError, "Data object did not respond to #next_page_token."
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
215
|
+
##
|
216
|
+
# Build a request for fetching the previous page of data
|
217
|
+
#
|
218
|
+
# @return [Google::APIClient::Request]
|
219
|
+
# API request for retrieving previous page, nil if no page token available
|
220
|
+
def prev_page
|
221
|
+
return nil unless self.prev_page_token
|
222
|
+
merged_parameters = Hash[self.reference.parameters].merge({
|
223
|
+
self.page_token_param => self.prev_page_token
|
224
|
+
})
|
225
|
+
# Because Requests can be coerced to Hashes, we can merge them,
|
226
|
+
# preserving all context except the API method parameters that we're
|
227
|
+
# using for pagination.
|
228
|
+
return Google::APIClient::Request.new(
|
229
|
+
Hash[self.reference].merge(:parameters => merged_parameters)
|
230
|
+
)
|
231
|
+
end
|
232
|
+
|
233
|
+
##
|
234
|
+
# Pagination scheme used by this request/response
|
235
|
+
#
|
236
|
+
# @!attribute [r] pagination_type
|
237
|
+
# @return [Symbol]
|
238
|
+
# currently always :token
|
239
|
+
def pagination_type
|
240
|
+
return :token
|
241
|
+
end
|
242
|
+
|
243
|
+
##
|
244
|
+
# Name of the field that contains the pagination token
|
245
|
+
#
|
246
|
+
# @!attribute [r] page_token_param
|
247
|
+
# @return [String]
|
248
|
+
# currently always 'pageToken'
|
249
|
+
def page_token_param
|
250
|
+
return "pageToken"
|
251
|
+
end
|
252
|
+
|
253
|
+
end
|
254
|
+
end
|
255
|
+
end
|