google-api-client 0.2.0 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +10 -0
- data/README.md +69 -0
- data/Rakefile +3 -4
- data/bin/google-api +49 -27
- data/lib/google/api_client.rb +164 -134
- data/lib/google/api_client/discovery.rb +4 -562
- data/lib/google/api_client/discovery/api.rb +272 -0
- data/lib/google/api_client/discovery/method.rb +313 -0
- data/lib/google/api_client/discovery/resource.rb +149 -0
- data/lib/google/api_client/discovery/schema.rb +106 -0
- data/lib/google/api_client/environment.rb +5 -2
- data/lib/google/api_client/errors.rb +10 -0
- data/lib/google/api_client/parser.rb +59 -0
- data/lib/google/api_client/parsers/json/error_parser.rb +34 -0
- data/lib/google/api_client/parsers/json/pagination.rb +40 -0
- data/lib/google/api_client/parsers/json_parser.rb +90 -12
- data/lib/google/api_client/reference.rb +202 -0
- data/lib/google/api_client/result.rb +132 -0
- data/lib/google/api_client/version.rb +10 -7
- data/lib/google/inflection.rb +7 -2
- data/spec/google/api_client/discovery_spec.rb +162 -123
- data/spec/google/api_client/parsers/json_parser_spec.rb +27 -23
- data/spec/google/api_client_spec.rb +3 -29
- data/tasks/gem.rake +26 -9
- data/tasks/rdoc.rake +12 -5
- data/tasks/spec.rake +4 -1
- data/tasks/wiki.rake +41 -0
- data/tasks/yard.rake +1 -1
- metadata +48 -95
- data/README +0 -68
@@ -0,0 +1,202 @@
|
|
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 'stringio'
|
16
|
+
require 'json'
|
17
|
+
require 'addressable/uri'
|
18
|
+
require 'google/api_client/discovery'
|
19
|
+
|
20
|
+
module Google
|
21
|
+
class APIClient
|
22
|
+
class Reference
|
23
|
+
def initialize(options={})
|
24
|
+
# We only need this to do lookups on method ID String values
|
25
|
+
# It's optional, but method ID lookups will fail if the client is
|
26
|
+
# omitted.
|
27
|
+
@client = options[:client]
|
28
|
+
@version = options[:version] || 'v1'
|
29
|
+
|
30
|
+
self.api_method = options[:api_method]
|
31
|
+
self.parameters = options[:parameters] || {}
|
32
|
+
# These parameters are handled differently because they're not
|
33
|
+
# parameters to the API method, but rather to the API system.
|
34
|
+
self.parameters['key'] ||= options[:key] if options[:key]
|
35
|
+
self.parameters['userIp'] ||= options[:user_ip] if options[:user_ip]
|
36
|
+
self.headers = options[:headers] || []
|
37
|
+
if options[:body]
|
38
|
+
self.body = options[:body]
|
39
|
+
elsif options[:merged_body]
|
40
|
+
self.merged_body = options[:merged_body]
|
41
|
+
elsif options[:body_object]
|
42
|
+
if options[:body_object].respond_to?(:to_json)
|
43
|
+
serialized_body = options[:body_object].to_json
|
44
|
+
elsif options[:body_object].respond_to?(:to_hash)
|
45
|
+
serialized_body = JSON.generate(options[:body_object].to_hash)
|
46
|
+
else
|
47
|
+
raise TypeError,
|
48
|
+
'Could not convert body object to JSON.' +
|
49
|
+
'Must respond to :to_json or :to_hash.'
|
50
|
+
end
|
51
|
+
self.merged_body = serialized_body
|
52
|
+
else
|
53
|
+
self.merged_body = ''
|
54
|
+
end
|
55
|
+
unless self.api_method
|
56
|
+
self.http_method = options[:http_method] || 'GET'
|
57
|
+
self.uri = options[:uri]
|
58
|
+
unless self.parameters.empty?
|
59
|
+
self.uri.query_values =
|
60
|
+
(self.uri.query_values || {}).merge(self.parameters)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def api_method
|
66
|
+
return @api_method
|
67
|
+
end
|
68
|
+
|
69
|
+
def api_method=(new_api_method)
|
70
|
+
if new_api_method.kind_of?(Google::APIClient::Method) ||
|
71
|
+
new_api_method == nil
|
72
|
+
@api_method = new_api_method
|
73
|
+
elsif new_api_method.respond_to?(:to_str) ||
|
74
|
+
new_api_method.kind_of?(Symbol)
|
75
|
+
unless @client
|
76
|
+
raise ArgumentError,
|
77
|
+
"API method lookup impossible without client instance."
|
78
|
+
end
|
79
|
+
new_api_method = new_api_method.to_s
|
80
|
+
# This method of guessing the API is unreliable. This will fail for
|
81
|
+
# APIs where the first segment of the RPC name does not match the
|
82
|
+
# service name. However, this is a fallback mechanism anyway.
|
83
|
+
# Developers should be passing in a reference to the method, rather
|
84
|
+
# than passing in a string or symbol. This should raise an error
|
85
|
+
# in the case of a mismatch.
|
86
|
+
api = new_api_method[/^([^.]+)\./, 1]
|
87
|
+
@api_method = @client.discovered_method(
|
88
|
+
new_api_method, api, @version
|
89
|
+
)
|
90
|
+
if @api_method
|
91
|
+
# Ditch the client reference, we won't need it again.
|
92
|
+
@client = nil
|
93
|
+
else
|
94
|
+
raise ArgumentError, "API method could not be found."
|
95
|
+
end
|
96
|
+
else
|
97
|
+
raise TypeError,
|
98
|
+
"Expected Google::APIClient::Method, got #{new_api_method.class}."
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
def parameters
|
103
|
+
return @parameters
|
104
|
+
end
|
105
|
+
|
106
|
+
def parameters=(new_parameters)
|
107
|
+
# No type-checking needed, the Method class handles this.
|
108
|
+
@parameters = new_parameters
|
109
|
+
end
|
110
|
+
|
111
|
+
def body
|
112
|
+
return @body
|
113
|
+
end
|
114
|
+
|
115
|
+
def body=(new_body)
|
116
|
+
if new_body.respond_to?(:each)
|
117
|
+
@body = new_body
|
118
|
+
else
|
119
|
+
raise TypeError, "Expected body to respond to :each."
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
def merged_body
|
124
|
+
return (self.body.inject(StringIO.new) do |accu, chunk|
|
125
|
+
accu.write(chunk)
|
126
|
+
accu
|
127
|
+
end).string
|
128
|
+
end
|
129
|
+
|
130
|
+
def merged_body=(new_merged_body)
|
131
|
+
if new_merged_body.respond_to?(:string)
|
132
|
+
new_merged_body = new_merged_body.string
|
133
|
+
elsif new_merged_body.respond_to?(:to_str)
|
134
|
+
new_merged_body = new_merged_body.to_str
|
135
|
+
else
|
136
|
+
raise TypeError,
|
137
|
+
"Expected String or StringIO, got #{new_merged_body.class}."
|
138
|
+
end
|
139
|
+
self.body = [new_merged_body]
|
140
|
+
end
|
141
|
+
|
142
|
+
def headers
|
143
|
+
return @headers ||= []
|
144
|
+
end
|
145
|
+
|
146
|
+
def headers=(new_headers)
|
147
|
+
if new_headers.kind_of?(Array) || new_headers.kind_of?(Hash)
|
148
|
+
@headers = new_headers
|
149
|
+
else
|
150
|
+
raise TypeError, "Expected Hash or Array, got #{new_headers.class}."
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
def http_method
|
155
|
+
return @http_method ||= self.api_method.http_method
|
156
|
+
end
|
157
|
+
|
158
|
+
def http_method=(new_http_method)
|
159
|
+
if new_http_method.kind_of?(Symbol)
|
160
|
+
@http_method = new_http_method.to_s.upcase
|
161
|
+
elsif new_http_method.respond_to?(:to_str)
|
162
|
+
@http_method = new_http_method.to_str.upcase
|
163
|
+
else
|
164
|
+
raise TypeError,
|
165
|
+
"Expected String or Symbol, got #{new_http_method.class}."
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
def uri
|
170
|
+
return @uri ||= self.api_method.generate_uri(self.parameters)
|
171
|
+
end
|
172
|
+
|
173
|
+
def uri=(new_uri)
|
174
|
+
@uri = Addressable::URI.parse(new_uri)
|
175
|
+
end
|
176
|
+
|
177
|
+
def to_request
|
178
|
+
if self.api_method
|
179
|
+
return self.api_method.generate_request(
|
180
|
+
self.parameters, self.merged_body, self.headers
|
181
|
+
)
|
182
|
+
else
|
183
|
+
return [self.http_method, self.uri, self.headers, self.body]
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
def to_hash
|
188
|
+
options = {}
|
189
|
+
if self.api_method
|
190
|
+
options[:api_method] = self.api_method
|
191
|
+
options[:parameters] = self.parameters
|
192
|
+
else
|
193
|
+
options[:http_method] = self.http_method
|
194
|
+
options[:uri] = self.uri
|
195
|
+
end
|
196
|
+
options[:headers] = self.headers
|
197
|
+
options[:body] = self.body
|
198
|
+
return options
|
199
|
+
end
|
200
|
+
end
|
201
|
+
end
|
202
|
+
end
|
@@ -0,0 +1,132 @@
|
|
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
|
+
module Google
|
16
|
+
class APIClient
|
17
|
+
##
|
18
|
+
# This class wraps a result returned by an API call.
|
19
|
+
class Result
|
20
|
+
def initialize(reference, request, response)
|
21
|
+
@reference = reference
|
22
|
+
@request = request
|
23
|
+
@response = response
|
24
|
+
end
|
25
|
+
|
26
|
+
attr_reader :reference
|
27
|
+
|
28
|
+
attr_reader :request
|
29
|
+
|
30
|
+
attr_reader :response
|
31
|
+
|
32
|
+
def status
|
33
|
+
return @response[0]
|
34
|
+
end
|
35
|
+
|
36
|
+
def headers
|
37
|
+
return @response[1]
|
38
|
+
end
|
39
|
+
|
40
|
+
def body
|
41
|
+
return @body ||= (begin
|
42
|
+
response_body = @response[2]
|
43
|
+
merged_body = (response_body.inject(StringIO.new) do |accu, chunk|
|
44
|
+
accu.write(chunk)
|
45
|
+
accu
|
46
|
+
end).string
|
47
|
+
end)
|
48
|
+
end
|
49
|
+
|
50
|
+
def data
|
51
|
+
return @data ||= (begin
|
52
|
+
_, content_type = self.headers.detect do |h, v|
|
53
|
+
h.downcase == 'Content-Type'.downcase
|
54
|
+
end
|
55
|
+
media_type = content_type[/^([^;]*);?.*$/, 1].strip.downcase
|
56
|
+
data = self.body
|
57
|
+
case media_type
|
58
|
+
when 'application/json'
|
59
|
+
data = ::JSON.parse(data)
|
60
|
+
# Strip data wrapper, if present
|
61
|
+
data = data['data'] if data.has_key?('data')
|
62
|
+
else
|
63
|
+
raise ArgumentError,
|
64
|
+
"Content-Type not supported for parsing: #{media_type}"
|
65
|
+
end
|
66
|
+
if @reference.api_method && @reference.api_method.response_schema
|
67
|
+
# Automatically parse using the schema designated for the
|
68
|
+
# response of this API method.
|
69
|
+
data = @reference.api_method.response_schema.new(data)
|
70
|
+
data
|
71
|
+
else
|
72
|
+
# Otherwise, return the raw unparsed value.
|
73
|
+
# This value must be indexable like a Hash.
|
74
|
+
data
|
75
|
+
end
|
76
|
+
end)
|
77
|
+
end
|
78
|
+
|
79
|
+
def pagination_type
|
80
|
+
return :token
|
81
|
+
end
|
82
|
+
|
83
|
+
def page_token_param
|
84
|
+
return "pageToken"
|
85
|
+
end
|
86
|
+
|
87
|
+
def next_page_token
|
88
|
+
if self.data.respond_to?(:next_page_token)
|
89
|
+
return self.data.next_page_token
|
90
|
+
elsif self.data.respond_to?(:[])
|
91
|
+
return self.data["nextPageToken"]
|
92
|
+
else
|
93
|
+
raise TypeError, "Data object did not respond to #next_page_token."
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
def next_page
|
98
|
+
merged_parameters = Hash[self.reference.parameters].merge({
|
99
|
+
self.page_token_param => self.next_page_token
|
100
|
+
})
|
101
|
+
# Because References can be coerced to Hashes, we can merge them,
|
102
|
+
# preserving all context except the API method parameters that we're
|
103
|
+
# using for pagination.
|
104
|
+
return Google::APIClient::Reference.new(
|
105
|
+
Hash[self.reference].merge(:parameters => merged_parameters)
|
106
|
+
)
|
107
|
+
end
|
108
|
+
|
109
|
+
def prev_page_token
|
110
|
+
if self.data.respond_to?(:prev_page_token)
|
111
|
+
return self.data.prev_page_token
|
112
|
+
elsif self.data.respond_to?(:[])
|
113
|
+
return self.data["prevPageToken"]
|
114
|
+
else
|
115
|
+
raise TypeError, "Data object did not respond to #next_page_token."
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
def prev_page
|
120
|
+
merged_parameters = Hash[self.reference.parameters].merge({
|
121
|
+
self.page_token_param => self.prev_page_token
|
122
|
+
})
|
123
|
+
# Because References can be coerced to Hashes, we can merge them,
|
124
|
+
# preserving all context except the API method parameters that we're
|
125
|
+
# using for pagination.
|
126
|
+
return Google::APIClient::Reference.new(
|
127
|
+
Hash[self.reference].merge(:parameters => merged_parameters)
|
128
|
+
)
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
@@ -13,14 +13,17 @@
|
|
13
13
|
# limitations under the License.
|
14
14
|
|
15
15
|
|
16
|
-
module
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
16
|
+
# Used to prevent the class/module from being loaded more than once
|
17
|
+
if !defined?(::Google::APIClient::VERSION)
|
18
|
+
module Google
|
19
|
+
class APIClient
|
20
|
+
module VERSION
|
21
|
+
MAJOR = 0
|
22
|
+
MINOR = 3
|
23
|
+
TINY = 0
|
22
24
|
|
23
|
-
|
25
|
+
STRING = [MAJOR, MINOR, TINY].join('.')
|
26
|
+
end
|
24
27
|
end
|
25
28
|
end
|
26
29
|
end
|
data/lib/google/inflection.rb
CHANGED
@@ -17,7 +17,12 @@ module Google
|
|
17
17
|
if defined?(ActiveSupport::Inflector)
|
18
18
|
INFLECTOR = ActiveSupport::Inflector
|
19
19
|
else
|
20
|
-
|
21
|
-
|
20
|
+
begin
|
21
|
+
require 'extlib/inflection'
|
22
|
+
INFLECTOR = Extlib::Inflection
|
23
|
+
rescue LoadError
|
24
|
+
require 'active_support/inflector'
|
25
|
+
INFLECTOR = ActiveSupport::Inflector
|
26
|
+
end
|
22
27
|
end
|
23
28
|
end
|
@@ -14,6 +14,7 @@
|
|
14
14
|
|
15
15
|
require 'spec_helper'
|
16
16
|
|
17
|
+
require 'json'
|
17
18
|
require 'signet/oauth_1/client'
|
18
19
|
require 'httpadapter/adapters/net_http'
|
19
20
|
|
@@ -66,6 +67,9 @@ describe Google::APIClient do
|
|
66
67
|
describe 'with the prediction API' do
|
67
68
|
before do
|
68
69
|
@client.authorization = nil
|
70
|
+
# The prediction API no longer exposes a v1, so we have to be
|
71
|
+
# careful about looking up the wrong API version.
|
72
|
+
@prediction = @client.discovered_api('prediction', 'v1.2')
|
69
73
|
end
|
70
74
|
|
71
75
|
it 'should correctly determine the discovery URI' do
|
@@ -73,46 +77,83 @@ describe Google::APIClient do
|
|
73
77
|
'https://www.googleapis.com/discovery/v1/apis/prediction/v1/rest'
|
74
78
|
end
|
75
79
|
|
80
|
+
it 'should correctly determine the discovery URI if :user_ip is set' do
|
81
|
+
@client.user_ip = '127.0.0.1'
|
82
|
+
request = @client.generate_request(
|
83
|
+
:http_method => 'GET',
|
84
|
+
:uri => @client.discovery_uri('prediction', 'v1.2'),
|
85
|
+
:authenticated => false
|
86
|
+
)
|
87
|
+
http_method, uri, headers, body = request
|
88
|
+
uri.should === (
|
89
|
+
'https://www.googleapis.com/discovery/v1/apis/prediction/v1.2/rest' +
|
90
|
+
'?userIp=127.0.0.1'
|
91
|
+
)
|
92
|
+
end
|
93
|
+
|
94
|
+
it 'should correctly determine the discovery URI if :key is set' do
|
95
|
+
@client.key = 'qwerty'
|
96
|
+
request = @client.generate_request(
|
97
|
+
:http_method => 'GET',
|
98
|
+
:uri => @client.discovery_uri('prediction', 'v1.2'),
|
99
|
+
:authenticated => false
|
100
|
+
)
|
101
|
+
http_method, uri, headers, body = request
|
102
|
+
uri.should === (
|
103
|
+
'https://www.googleapis.com/discovery/v1/apis/prediction/v1.2/rest' +
|
104
|
+
'?key=qwerty'
|
105
|
+
)
|
106
|
+
end
|
107
|
+
|
108
|
+
it 'should correctly determine the discovery URI if both are set' do
|
109
|
+
@client.key = 'qwerty'
|
110
|
+
@client.user_ip = '127.0.0.1'
|
111
|
+
request = @client.generate_request(
|
112
|
+
:http_method => 'GET',
|
113
|
+
:uri => @client.discovery_uri('prediction', 'v1.2'),
|
114
|
+
:authenticated => false
|
115
|
+
)
|
116
|
+
http_method, uri, headers, body = request
|
117
|
+
uri.should === (
|
118
|
+
'https://www.googleapis.com/discovery/v1/apis/prediction/v1.2/rest' +
|
119
|
+
'?key=qwerty&userIp=127.0.0.1'
|
120
|
+
)
|
121
|
+
end
|
122
|
+
|
76
123
|
it 'should correctly generate API objects' do
|
77
|
-
@client.discovered_api('prediction').name.should == 'prediction'
|
78
|
-
@client.discovered_api('prediction').version.should == 'v1'
|
79
|
-
@client.discovered_api(:prediction).name.should == 'prediction'
|
80
|
-
@client.discovered_api(:prediction).version.should == 'v1'
|
124
|
+
@client.discovered_api('prediction', 'v1.2').name.should == 'prediction'
|
125
|
+
@client.discovered_api('prediction', 'v1.2').version.should == 'v1.2'
|
126
|
+
@client.discovered_api(:prediction, 'v1.2').name.should == 'prediction'
|
127
|
+
@client.discovered_api(:prediction, 'v1.2').version.should == 'v1.2'
|
81
128
|
end
|
82
129
|
|
83
130
|
it 'should discover methods' do
|
84
131
|
@client.discovered_method(
|
85
|
-
'prediction.training.insert', 'prediction'
|
132
|
+
'prediction.training.insert', 'prediction', 'v1.2'
|
86
133
|
).name.should == 'insert'
|
87
134
|
@client.discovered_method(
|
88
|
-
:'prediction.training.insert', :prediction
|
135
|
+
:'prediction.training.insert', :prediction, 'v1.2'
|
89
136
|
).name.should == 'insert'
|
90
|
-
end
|
91
|
-
|
92
|
-
it 'should discover methods' do
|
93
137
|
@client.discovered_method(
|
94
|
-
'prediction.training.delete', 'prediction', 'v1.
|
138
|
+
'prediction.training.delete', 'prediction', 'v1.2'
|
95
139
|
).name.should == 'delete'
|
96
140
|
end
|
97
141
|
|
98
142
|
it 'should not find methods that are not in the discovery document' do
|
99
143
|
@client.discovered_method(
|
100
|
-
'prediction.
|
101
|
-
).should == nil
|
102
|
-
@client.discovered_method(
|
103
|
-
'prediction.bogus', 'prediction', 'v1'
|
144
|
+
'prediction.bogus', 'prediction', 'v1.2'
|
104
145
|
).should == nil
|
105
146
|
end
|
106
147
|
|
107
148
|
it 'should raise an error for bogus methods' do
|
108
149
|
(lambda do
|
109
|
-
@client.discovered_method(42, 'prediction', 'v1')
|
150
|
+
@client.discovered_method(42, 'prediction', 'v1.2')
|
110
151
|
end).should raise_error(TypeError)
|
111
152
|
end
|
112
153
|
|
113
154
|
it 'should raise an error for bogus methods' do
|
114
155
|
(lambda do
|
115
|
-
@client.generate_request(@client.discovered_api('prediction'))
|
156
|
+
@client.generate_request(@client.discovered_api('prediction', 'v1.2'))
|
116
157
|
end).should raise_error(TypeError)
|
117
158
|
end
|
118
159
|
|
@@ -123,49 +164,50 @@ describe Google::APIClient do
|
|
123
164
|
|
124
165
|
it 'should generate valid requests' do
|
125
166
|
request = @client.generate_request(
|
126
|
-
|
127
|
-
{'data' => '12345', }
|
167
|
+
:api_method => @prediction.training.insert,
|
168
|
+
:parameters => {'data' => '12345', }
|
128
169
|
)
|
129
170
|
method, uri, headers, body = request
|
130
171
|
method.should == 'POST'
|
131
172
|
uri.should ==
|
132
|
-
'https://www.googleapis.com/prediction/v1/training?data=12345'
|
173
|
+
'https://www.googleapis.com/prediction/v1.2/training?data=12345'
|
133
174
|
(headers.inject({}) { |h,(k,v)| h[k]=v; h }).should == {}
|
134
175
|
body.should respond_to(:each)
|
135
176
|
end
|
136
177
|
|
137
178
|
it 'should generate requests against the correct URIs' do
|
138
179
|
request = @client.generate_request(
|
139
|
-
:
|
140
|
-
{'data' => '12345'}
|
180
|
+
:api_method => @prediction.training.insert,
|
181
|
+
:parameters => {'data' => '12345'}
|
141
182
|
)
|
142
183
|
method, uri, headers, body = request
|
143
184
|
uri.should ==
|
144
|
-
'https://www.googleapis.com/prediction/v1/training?data=12345'
|
185
|
+
'https://www.googleapis.com/prediction/v1.2/training?data=12345'
|
145
186
|
end
|
146
187
|
|
147
188
|
it 'should generate requests against the correct URIs' do
|
148
|
-
prediction = @client.discovered_api('prediction', 'v1')
|
149
189
|
request = @client.generate_request(
|
150
|
-
prediction.training.insert,
|
151
|
-
{'data' => '12345'}
|
190
|
+
:api_method => @prediction.training.insert,
|
191
|
+
:parameters => {'data' => '12345'}
|
152
192
|
)
|
153
193
|
method, uri, headers, body = request
|
154
194
|
uri.should ==
|
155
|
-
'https://www.googleapis.com/prediction/v1/training?data=12345'
|
195
|
+
'https://www.googleapis.com/prediction/v1.2/training?data=12345'
|
156
196
|
end
|
157
197
|
|
158
198
|
it 'should allow modification to the base URIs for testing purposes' do
|
159
|
-
prediction = @client.discovered_api('prediction', 'v1')
|
199
|
+
prediction = @client.discovered_api('prediction', 'v1.2')
|
160
200
|
prediction.method_base =
|
161
|
-
'https://testing-domain.googleapis.com/prediction/v1/'
|
201
|
+
'https://testing-domain.googleapis.com/prediction/v1.2/'
|
162
202
|
request = @client.generate_request(
|
163
|
-
prediction.training.insert,
|
164
|
-
{'data' => '123'}
|
203
|
+
:api_method => prediction.training.insert,
|
204
|
+
:parameters => {'data' => '123'}
|
165
205
|
)
|
166
206
|
method, uri, headers, body = request
|
167
|
-
uri.should ==
|
168
|
-
'https://testing-domain.googleapis.com/
|
207
|
+
uri.should == (
|
208
|
+
'https://testing-domain.googleapis.com/' +
|
209
|
+
'prediction/v1.2/training?data=123'
|
210
|
+
)
|
169
211
|
end
|
170
212
|
|
171
213
|
it 'should generate OAuth 1 requests' do
|
@@ -173,8 +215,8 @@ describe Google::APIClient do
|
|
173
215
|
@client.authorization.token_credential_key = '12345'
|
174
216
|
@client.authorization.token_credential_secret = '12345'
|
175
217
|
request = @client.generate_request(
|
176
|
-
|
177
|
-
{'data' => '12345'}
|
218
|
+
:api_method => @prediction.training.insert,
|
219
|
+
:parameters => {'data' => '12345'}
|
178
220
|
)
|
179
221
|
method, uri, headers, body = request
|
180
222
|
headers = headers.inject({}) { |h,(k,v)| h[k]=v; h }
|
@@ -186,8 +228,8 @@ describe Google::APIClient do
|
|
186
228
|
@client.authorization = :oauth_2
|
187
229
|
@client.authorization.access_token = '12345'
|
188
230
|
request = @client.generate_request(
|
189
|
-
|
190
|
-
{'data' => '12345'}
|
231
|
+
:api_method => @prediction.training.insert,
|
232
|
+
:parameters => {'data' => '12345'}
|
191
233
|
)
|
192
234
|
method, uri, headers, body = request
|
193
235
|
headers = headers.inject({}) { |h,(k,v)| h[k]=v; h }
|
@@ -199,88 +241,112 @@ describe Google::APIClient do
|
|
199
241
|
@client.authorization = :oauth_1
|
200
242
|
@client.authorization.token_credential_key = '12345'
|
201
243
|
@client.authorization.token_credential_secret = '12345'
|
202
|
-
|
203
|
-
|
244
|
+
result = @client.execute(
|
245
|
+
@prediction.training.insert,
|
204
246
|
{'data' => '12345'}
|
205
247
|
)
|
206
|
-
status, headers, body = response
|
248
|
+
status, headers, body = result.response
|
207
249
|
status.should == 401
|
208
250
|
end
|
209
251
|
|
210
252
|
it 'should not be able to execute improperly authorized requests' do
|
211
253
|
@client.authorization = :oauth_2
|
212
254
|
@client.authorization.access_token = '12345'
|
213
|
-
|
214
|
-
|
255
|
+
result = @client.execute(
|
256
|
+
@prediction.training.insert,
|
215
257
|
{'data' => '12345'}
|
216
258
|
)
|
217
|
-
status, headers, body = response
|
259
|
+
status, headers, body = result.response
|
218
260
|
status.should == 401
|
219
261
|
end
|
262
|
+
|
263
|
+
it 'should not be able to execute improperly authorized requests' do
|
264
|
+
(lambda do
|
265
|
+
@client.authorization = :oauth_1
|
266
|
+
@client.authorization.token_credential_key = '12345'
|
267
|
+
@client.authorization.token_credential_secret = '12345'
|
268
|
+
result = @client.execute!(
|
269
|
+
@prediction.training.insert,
|
270
|
+
{'data' => '12345'}
|
271
|
+
)
|
272
|
+
end).should raise_error(Google::APIClient::ClientError)
|
273
|
+
end
|
274
|
+
|
275
|
+
it 'should not be able to execute improperly authorized requests' do
|
276
|
+
(lambda do
|
277
|
+
@client.authorization = :oauth_2
|
278
|
+
@client.authorization.access_token = '12345'
|
279
|
+
result = @client.execute!(
|
280
|
+
@prediction.training.insert,
|
281
|
+
{'data' => '12345'}
|
282
|
+
)
|
283
|
+
end).should raise_error(Google::APIClient::ClientError)
|
284
|
+
end
|
285
|
+
|
286
|
+
it 'should correctly handle unnamed parameters' do
|
287
|
+
@client.authorization = :oauth_2
|
288
|
+
@client.authorization.access_token = '12345'
|
289
|
+
result = @client.execute(
|
290
|
+
@prediction.training.insert,
|
291
|
+
{},
|
292
|
+
JSON.generate({"id" => "bucket/object"}),
|
293
|
+
{'Content-Type' => 'application/json'}
|
294
|
+
)
|
295
|
+
method, uri, headers, body = result.request
|
296
|
+
Hash[headers]['Content-Type'].should == 'application/json'
|
297
|
+
end
|
220
298
|
end
|
221
299
|
|
222
|
-
describe 'with the
|
300
|
+
describe 'with the plus API' do
|
223
301
|
before do
|
224
302
|
@client.authorization = nil
|
225
|
-
@
|
303
|
+
@plus = @client.discovered_api('plus')
|
226
304
|
end
|
227
305
|
|
228
306
|
it 'should correctly determine the discovery URI' do
|
229
|
-
@client.discovery_uri('
|
230
|
-
'https://www.googleapis.com/discovery/v1/apis/
|
307
|
+
@client.discovery_uri('plus').should ===
|
308
|
+
'https://www.googleapis.com/discovery/v1/apis/plus/v1/rest'
|
231
309
|
end
|
232
310
|
|
233
311
|
it 'should find APIs that are in the discovery document' do
|
234
|
-
@client.discovered_api('
|
235
|
-
@client.discovered_api('
|
236
|
-
@client.discovered_api(:
|
237
|
-
@client.discovered_api(:
|
312
|
+
@client.discovered_api('plus').name.should == 'plus'
|
313
|
+
@client.discovered_api('plus').version.should == 'v1'
|
314
|
+
@client.discovered_api(:plus).name.should == 'plus'
|
315
|
+
@client.discovered_api(:plus).version.should == 'v1'
|
238
316
|
end
|
239
317
|
|
240
318
|
it 'should find methods that are in the discovery document' do
|
241
319
|
# TODO(bobaman) Fix this when the RPC names are correct
|
242
320
|
@client.discovered_method(
|
243
|
-
'
|
321
|
+
'plus.activities.list', 'plus'
|
244
322
|
).name.should == 'list'
|
245
323
|
end
|
246
324
|
|
247
325
|
it 'should not find methods that are not in the discovery document' do
|
248
|
-
@client.discovered_method('
|
249
|
-
end
|
250
|
-
|
251
|
-
it 'should fail for string RPC names that do not match API name' do
|
252
|
-
(lambda do
|
253
|
-
@client.generate_request(
|
254
|
-
'chili.activities.list',
|
255
|
-
{'alt' => 'json'},
|
256
|
-
'',
|
257
|
-
[],
|
258
|
-
{:signed => false}
|
259
|
-
)
|
260
|
-
end).should raise_error(Google::APIClient::TransmissionError)
|
326
|
+
@client.discovered_method('plus.bogus', 'plus').should == nil
|
261
327
|
end
|
262
328
|
|
263
329
|
it 'should generate requests against the correct URIs' do
|
264
330
|
request = @client.generate_request(
|
265
|
-
@
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
331
|
+
:api_method => @plus.activities.list,
|
332
|
+
:parameters => {
|
333
|
+
'userId' => '107807692475771887386', 'collection' => 'public'
|
334
|
+
},
|
335
|
+
:authenticated => false
|
270
336
|
)
|
271
337
|
method, uri, headers, body = request
|
272
|
-
uri.should ==
|
273
|
-
'https://www.googleapis.com/
|
338
|
+
uri.should == (
|
339
|
+
'https://www.googleapis.com/plus/v1/' +
|
340
|
+
'people/107807692475771887386/activities/public'
|
341
|
+
)
|
274
342
|
end
|
275
343
|
|
276
344
|
it 'should correctly validate parameters' do
|
277
345
|
(lambda do
|
278
346
|
@client.generate_request(
|
279
|
-
@
|
280
|
-
{'alt' => 'json'},
|
281
|
-
|
282
|
-
[],
|
283
|
-
{:signed => false}
|
347
|
+
:api_method => @plus.activities.list,
|
348
|
+
:parameters => {'alt' => 'json'},
|
349
|
+
:authenticated => false
|
284
350
|
)
|
285
351
|
end).should raise_error(ArgumentError)
|
286
352
|
end
|
@@ -288,26 +354,14 @@ describe Google::APIClient do
|
|
288
354
|
it 'should correctly validate parameters' do
|
289
355
|
(lambda do
|
290
356
|
@client.generate_request(
|
291
|
-
@
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
357
|
+
:api_method => @plus.activities.list,
|
358
|
+
:parameters => {
|
359
|
+
'userId' => '107807692475771887386', 'collection' => 'bogus'
|
360
|
+
},
|
361
|
+
:authenticated => false
|
296
362
|
)
|
297
363
|
end).should raise_error(ArgumentError)
|
298
364
|
end
|
299
|
-
|
300
|
-
it 'should be able to execute requests without authorization' do
|
301
|
-
response = @client.execute(
|
302
|
-
@buzz.activities.list,
|
303
|
-
{'alt' => 'json', 'userId' => 'hikingfan', 'scope' => '@public'},
|
304
|
-
'',
|
305
|
-
[],
|
306
|
-
{:signed => false}
|
307
|
-
)
|
308
|
-
status, headers, body = response
|
309
|
-
status.should == 200
|
310
|
-
end
|
311
365
|
end
|
312
366
|
|
313
367
|
describe 'with the latitude API' do
|
@@ -338,11 +392,8 @@ describe Google::APIClient do
|
|
338
392
|
|
339
393
|
it 'should generate requests against the correct URIs' do
|
340
394
|
request = @client.generate_request(
|
341
|
-
'latitude.currentLocation.get',
|
342
|
-
|
343
|
-
'',
|
344
|
-
[],
|
345
|
-
{:signed => false}
|
395
|
+
:api_method => 'latitude.currentLocation.get',
|
396
|
+
:authenticated => false
|
346
397
|
)
|
347
398
|
method, uri, headers, body = request
|
348
399
|
uri.should ==
|
@@ -351,11 +402,8 @@ describe Google::APIClient do
|
|
351
402
|
|
352
403
|
it 'should generate requests against the correct URIs' do
|
353
404
|
request = @client.generate_request(
|
354
|
-
@latitude.current_location.get,
|
355
|
-
|
356
|
-
'',
|
357
|
-
[],
|
358
|
-
{:signed => false}
|
405
|
+
:api_method => @latitude.current_location.get,
|
406
|
+
:authenticated => false
|
359
407
|
)
|
360
408
|
method, uri, headers, body = request
|
361
409
|
uri.should ==
|
@@ -363,14 +411,11 @@ describe Google::APIClient do
|
|
363
411
|
end
|
364
412
|
|
365
413
|
it 'should not be able to execute requests without authorization' do
|
366
|
-
|
367
|
-
'latitude.currentLocation.get',
|
368
|
-
|
369
|
-
'',
|
370
|
-
[],
|
371
|
-
{:signed => false}
|
414
|
+
result = @client.execute(
|
415
|
+
:api_method => 'latitude.currentLocation.get',
|
416
|
+
:authenticated => false
|
372
417
|
)
|
373
|
-
status, headers, body = response
|
418
|
+
status, headers, body = result.response
|
374
419
|
status.should == 401
|
375
420
|
end
|
376
421
|
end
|
@@ -403,11 +448,8 @@ describe Google::APIClient do
|
|
403
448
|
|
404
449
|
it 'should generate requests against the correct URIs' do
|
405
450
|
request = @client.generate_request(
|
406
|
-
'moderator.profiles.get',
|
407
|
-
|
408
|
-
'',
|
409
|
-
[],
|
410
|
-
{:signed => false}
|
451
|
+
:api_method => 'moderator.profiles.get',
|
452
|
+
:authenticated => false
|
411
453
|
)
|
412
454
|
method, uri, headers, body = request
|
413
455
|
uri.should ==
|
@@ -416,11 +458,8 @@ describe Google::APIClient do
|
|
416
458
|
|
417
459
|
it 'should generate requests against the correct URIs' do
|
418
460
|
request = @client.generate_request(
|
419
|
-
@moderator.profiles.get,
|
420
|
-
|
421
|
-
'',
|
422
|
-
[],
|
423
|
-
{:signed => false}
|
461
|
+
:api_method => @moderator.profiles.get,
|
462
|
+
:authenticated => false
|
424
463
|
)
|
425
464
|
method, uri, headers, body = request
|
426
465
|
uri.should ==
|
@@ -428,14 +467,14 @@ describe Google::APIClient do
|
|
428
467
|
end
|
429
468
|
|
430
469
|
it 'should not be able to execute requests without authorization' do
|
431
|
-
|
470
|
+
result = @client.execute(
|
432
471
|
'moderator.profiles.get',
|
433
472
|
{},
|
434
473
|
'',
|
435
474
|
[],
|
436
|
-
{:
|
475
|
+
{:authenticated => false}
|
437
476
|
)
|
438
|
-
status, headers, body = response
|
477
|
+
status, headers, body = result.response
|
439
478
|
status.should == 401
|
440
479
|
end
|
441
480
|
end
|