Merge branch 'schemas'
* Resolved some test failures that showed up during the merge. Conflicts: lib/google/api_client/discovery/api.rb
This commit is contained in:
commit
66ed5248ad
|
@ -16,3 +16,4 @@
|
||||||
require 'google/api_client/discovery/api'
|
require 'google/api_client/discovery/api'
|
||||||
require 'google/api_client/discovery/resource'
|
require 'google/api_client/discovery/resource'
|
||||||
require 'google/api_client/discovery/method'
|
require 'google/api_client/discovery/method'
|
||||||
|
require 'google/api_client/discovery/schema'
|
||||||
|
|
|
@ -62,7 +62,10 @@ module Google
|
||||||
#
|
#
|
||||||
# @return [String] The service id.
|
# @return [String] The service id.
|
||||||
def id
|
def id
|
||||||
return @discovery_document['id']
|
return (
|
||||||
|
@discovery_document['id'] ||
|
||||||
|
"#{self.name}:#{self.version}"
|
||||||
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
##
|
##
|
||||||
|
@ -168,15 +171,47 @@ module Google
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
##
|
||||||
|
# A list of schemas available for this version of the API.
|
||||||
|
#
|
||||||
|
# @return [Hash] A list of {Google::APIClient::Schema} objects.
|
||||||
|
def schemas
|
||||||
|
return @schemas ||= (
|
||||||
|
(@discovery_document['schemas'] || []).inject({}) do |accu, (k, v)|
|
||||||
|
accu[k] = Google::APIClient::Schema.parse(self, v)
|
||||||
|
accu
|
||||||
|
end
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
##
|
||||||
|
# Returns a schema for a kind value.
|
||||||
|
#
|
||||||
|
# @return [Google::APIClient::Schema] The associated Schema object.
|
||||||
|
def schema_for_kind(kind)
|
||||||
|
api_name, schema_name = kind.split('#', 2)
|
||||||
|
if api_name != self.name
|
||||||
|
raise ArgumentError,
|
||||||
|
"The kind does not match this API. " +
|
||||||
|
"Expected '#{self.name}', got '#{api_name}'."
|
||||||
|
end
|
||||||
|
for k, v in self.schemas
|
||||||
|
return v if k.downcase == schema_name.downcase
|
||||||
|
end
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
##
|
##
|
||||||
# A list of resources available at the root level of this version of the
|
# A list of resources available at the root level of this version of the
|
||||||
# service.
|
# API.
|
||||||
#
|
#
|
||||||
# @return [Array] A list of {Google::APIClient::Resource} objects.
|
# @return [Array] A list of {Google::APIClient::Resource} objects.
|
||||||
def resources
|
def resources
|
||||||
return @resources ||= (
|
return @resources ||= (
|
||||||
(@discovery_document['resources'] || []).inject([]) do |accu, (k, v)|
|
(@discovery_document['resources'] || []).inject([]) do |accu, (k, v)|
|
||||||
accu << Google::APIClient::Resource.new(self.method_base, k, v)
|
accu << Google::APIClient::Resource.new(
|
||||||
|
self, self.method_base, k, v
|
||||||
|
)
|
||||||
accu
|
accu
|
||||||
end
|
end
|
||||||
)
|
)
|
||||||
|
@ -184,13 +219,13 @@ module Google
|
||||||
|
|
||||||
##
|
##
|
||||||
# A list of methods available at the root level of this version of the
|
# A list of methods available at the root level of this version of the
|
||||||
# service.
|
# API.
|
||||||
#
|
#
|
||||||
# @return [Array] A list of {Google::APIClient::Method} objects.
|
# @return [Array] A list of {Google::APIClient::Method} objects.
|
||||||
def methods
|
def methods
|
||||||
return @methods ||= (
|
return @methods ||= (
|
||||||
(@discovery_document['methods'] || []).inject([]) do |accu, (k, v)|
|
(@discovery_document['methods'] || []).inject([]) do |accu, (k, v)|
|
||||||
accu << Google::APIClient::Method.new(self.method_base, k, v)
|
accu << Google::APIClient::Method.new(self, self.method_base, k, v)
|
||||||
accu
|
accu
|
||||||
end
|
end
|
||||||
)
|
)
|
||||||
|
|
|
@ -35,7 +35,8 @@ module Google
|
||||||
# The section of the discovery document that applies to this method.
|
# The section of the discovery document that applies to this method.
|
||||||
#
|
#
|
||||||
# @return [Google::APIClient::Method] The constructed method object.
|
# @return [Google::APIClient::Method] The constructed method object.
|
||||||
def initialize(method_base, method_name, discovery_document)
|
def initialize(api, method_base, method_name, discovery_document)
|
||||||
|
@api = api
|
||||||
@method_base = method_base
|
@method_base = method_base
|
||||||
@name = method_name
|
@name = method_name
|
||||||
@discovery_document = discovery_document
|
@discovery_document = discovery_document
|
||||||
|
@ -102,6 +103,32 @@ module Google
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
##
|
||||||
|
# Returns the Schema object for the method's request, if any.
|
||||||
|
#
|
||||||
|
# @return [Google::APIClient::Schema] The request schema.
|
||||||
|
def request_schema
|
||||||
|
if @discovery_document['request']
|
||||||
|
schema_name = @discovery_document['request']['$ref']
|
||||||
|
return @api.schemas[schema_name]
|
||||||
|
else
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
##
|
||||||
|
# Returns the Schema object for the method's response, if any.
|
||||||
|
#
|
||||||
|
# @return [Google::APIClient::Schema] The response schema.
|
||||||
|
def response_schema
|
||||||
|
if @discovery_document['response']
|
||||||
|
schema_name = @discovery_document['response']['$ref']
|
||||||
|
return @api.schemas[schema_name]
|
||||||
|
else
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
##
|
##
|
||||||
# Normalizes parameters, converting to the appropriate types.
|
# Normalizes parameters, converting to the appropriate types.
|
||||||
#
|
#
|
||||||
|
|
|
@ -35,7 +35,8 @@ module Google
|
||||||
# The section of the discovery document that applies to this resource.
|
# The section of the discovery document that applies to this resource.
|
||||||
#
|
#
|
||||||
# @return [Google::APIClient::Resource] The constructed resource object.
|
# @return [Google::APIClient::Resource] The constructed resource object.
|
||||||
def initialize(method_base, resource_name, discovery_document)
|
def initialize(api, method_base, resource_name, discovery_document)
|
||||||
|
@api = api
|
||||||
@method_base = method_base
|
@method_base = method_base
|
||||||
@name = resource_name
|
@name = resource_name
|
||||||
@discovery_document = discovery_document
|
@discovery_document = discovery_document
|
||||||
|
@ -95,7 +96,9 @@ module Google
|
||||||
def resources
|
def resources
|
||||||
return @resources ||= (
|
return @resources ||= (
|
||||||
(@discovery_document['resources'] || []).inject([]) do |accu, (k, v)|
|
(@discovery_document['resources'] || []).inject([]) do |accu, (k, v)|
|
||||||
accu << Google::APIClient::Resource.new(self.method_base, k, v)
|
accu << Google::APIClient::Resource.new(
|
||||||
|
@api, self.method_base, k, v
|
||||||
|
)
|
||||||
accu
|
accu
|
||||||
end
|
end
|
||||||
)
|
)
|
||||||
|
@ -108,7 +111,7 @@ module Google
|
||||||
def methods
|
def methods
|
||||||
return @methods ||= (
|
return @methods ||= (
|
||||||
(@discovery_document['methods'] || []).inject([]) do |accu, (k, v)|
|
(@discovery_document['methods'] || []).inject([]) do |accu, (k, v)|
|
||||||
accu << Google::APIClient::Method.new(self.method_base, k, v)
|
accu << Google::APIClient::Method.new(@api, self.method_base, k, v)
|
||||||
accu
|
accu
|
||||||
end
|
end
|
||||||
)
|
)
|
||||||
|
|
|
@ -0,0 +1,106 @@
|
||||||
|
# Copyright 2010 Google Inc.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
|
||||||
|
|
||||||
|
require 'time'
|
||||||
|
require 'json'
|
||||||
|
require 'base64'
|
||||||
|
require 'autoparse'
|
||||||
|
require 'addressable/uri'
|
||||||
|
require 'addressable/template'
|
||||||
|
|
||||||
|
require 'google/inflection'
|
||||||
|
require 'google/api_client/errors'
|
||||||
|
|
||||||
|
module Google
|
||||||
|
class APIClient
|
||||||
|
module Schema
|
||||||
|
def self.parse(api, schema_data)
|
||||||
|
# This method is super-long, but hard to break up due to the
|
||||||
|
# unavoidable dependence on closures and execution context.
|
||||||
|
schema_name = schema_data['id']
|
||||||
|
|
||||||
|
# Due to an oversight, schema IDs may not be URI references.
|
||||||
|
# TODO(bobaman): Remove this code once this has been resolved.
|
||||||
|
schema_uri = (
|
||||||
|
api.document_base +
|
||||||
|
(schema_name[0..0] != '#' ? '#' + schema_name : schema_name)
|
||||||
|
)
|
||||||
|
# puts schema_uri
|
||||||
|
|
||||||
|
# Due to an oversight, schema IDs may not be URI references.
|
||||||
|
# TODO(bobaman): Remove this whole lambda once this has been resolved.
|
||||||
|
reformat_references = lambda do |data|
|
||||||
|
# This code is not particularly efficient due to recursive traversal
|
||||||
|
# and excess object creation, but this hopefully shouldn't be an
|
||||||
|
# issue since it should only be called only once per schema per
|
||||||
|
# process.
|
||||||
|
if data.kind_of?(Hash) && data['$ref']
|
||||||
|
reference = data['$ref']
|
||||||
|
reference = '#' + reference if reference[0..0] != '#'
|
||||||
|
data.merge({
|
||||||
|
'$ref' => reference
|
||||||
|
})
|
||||||
|
elsif data.kind_of?(Hash)
|
||||||
|
data.inject({}) do |accu, (key, value)|
|
||||||
|
if value.kind_of?(Hash)
|
||||||
|
accu[key] = reformat_references.call(value)
|
||||||
|
else
|
||||||
|
accu[key] = value
|
||||||
|
end
|
||||||
|
accu
|
||||||
|
end
|
||||||
|
else
|
||||||
|
data
|
||||||
|
end
|
||||||
|
end
|
||||||
|
schema_data = reformat_references.call(schema_data)
|
||||||
|
# puts schema_data.inspect
|
||||||
|
|
||||||
|
if schema_name
|
||||||
|
api_name_string =
|
||||||
|
Google::INFLECTOR.camelize(api.name)
|
||||||
|
api_version_string =
|
||||||
|
Google::INFLECTOR.camelize(api.version).gsub('.', '_')
|
||||||
|
if Google::APIClient::Schema.const_defined?(api_name_string)
|
||||||
|
api_name = Google::APIClient::Schema.const_get(api_name_string)
|
||||||
|
else
|
||||||
|
api_name = Google::APIClient::Schema.const_set(
|
||||||
|
api_name_string, Module.new
|
||||||
|
)
|
||||||
|
end
|
||||||
|
if api_name.const_defined?(api_version_string)
|
||||||
|
api_version = api_name.const_get(api_version_string)
|
||||||
|
else
|
||||||
|
api_version = api_name.const_set(api_version_string, Module.new)
|
||||||
|
end
|
||||||
|
if api_version.const_defined?(schema_name)
|
||||||
|
schema_class = api_version.const_get(schema_name)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# It's possible the schema has already been defined. If so, don't
|
||||||
|
# redefine it. This means that reloading a schema which has already
|
||||||
|
# been loaded into memory is not possible.
|
||||||
|
unless schema_class
|
||||||
|
schema_class = AutoParse.generate(schema_data, :uri => schema_uri)
|
||||||
|
if schema_name
|
||||||
|
api_version.const_set(schema_name, schema_class)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return schema_class
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -12,8 +12,6 @@
|
||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
|
|
||||||
require 'google/api_client/parsers/json_parser'
|
|
||||||
|
|
||||||
module Google
|
module Google
|
||||||
class APIClient
|
class APIClient
|
||||||
##
|
##
|
||||||
|
@ -54,9 +52,27 @@ module Google
|
||||||
_, content_type = self.headers.detect do |h, v|
|
_, content_type = self.headers.detect do |h, v|
|
||||||
h.downcase == 'Content-Type'.downcase
|
h.downcase == 'Content-Type'.downcase
|
||||||
end
|
end
|
||||||
parser_type =
|
media_type = content_type[/^([^;]*);?.*$/, 1].strip.downcase
|
||||||
Google::APIClient::Parser.match_content_type(content_type)
|
data = self.body
|
||||||
parser_type.parse(self.body)
|
case media_type
|
||||||
|
when 'application/json'
|
||||||
|
data = ::JSON.parse(data)
|
||||||
|
# Strip data wrapper, if present
|
||||||
|
data = data['data'] if data.has_key?('data')
|
||||||
|
else
|
||||||
|
raise ArgumentError,
|
||||||
|
"Content-Type not supported for parsing: #{media_type}"
|
||||||
|
end
|
||||||
|
if @reference.api_method && @reference.api_method.response_schema
|
||||||
|
# Automatically parse using the schema designated for the
|
||||||
|
# response of this API method.
|
||||||
|
data = @reference.api_method.response_schema.new(data)
|
||||||
|
data
|
||||||
|
else
|
||||||
|
# Otherwise, return the raw unparsed value.
|
||||||
|
# This value must be indexable like a Hash.
|
||||||
|
data
|
||||||
|
end
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -297,60 +297,54 @@ describe Google::APIClient do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe 'with the buzz API' do
|
describe 'with the plus API' do
|
||||||
before do
|
before do
|
||||||
@client.authorization = nil
|
@client.authorization = nil
|
||||||
@buzz = @client.discovered_api('buzz')
|
@plus = @client.discovered_api('plus')
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'should correctly determine the discovery URI' do
|
it 'should correctly determine the discovery URI' do
|
||||||
@client.discovery_uri('buzz').should ===
|
@client.discovery_uri('plus').should ===
|
||||||
'https://www.googleapis.com/discovery/v1/apis/buzz/v1/rest'
|
'https://www.googleapis.com/discovery/v1/apis/plus/v1/rest'
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'should find APIs that are in the discovery document' do
|
it 'should find APIs that are in the discovery document' do
|
||||||
@client.discovered_api('buzz').name.should == 'buzz'
|
@client.discovered_api('plus').name.should == 'plus'
|
||||||
@client.discovered_api('buzz').version.should == 'v1'
|
@client.discovered_api('plus').version.should == 'v1'
|
||||||
@client.discovered_api(:buzz).name.should == 'buzz'
|
@client.discovered_api(:plus).name.should == 'plus'
|
||||||
@client.discovered_api(:buzz).version.should == 'v1'
|
@client.discovered_api(:plus).version.should == 'v1'
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'should find methods that are in the discovery document' do
|
it 'should find methods that are in the discovery document' do
|
||||||
# TODO(bobaman) Fix this when the RPC names are correct
|
# TODO(bobaman) Fix this when the RPC names are correct
|
||||||
@client.discovered_method(
|
@client.discovered_method(
|
||||||
'chili.activities.list', 'buzz'
|
'plus.activities.list', 'plus'
|
||||||
).name.should == 'list'
|
).name.should == 'list'
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'should not find methods that are not in the discovery document' do
|
it 'should not find methods that are not in the discovery document' do
|
||||||
@client.discovered_method('buzz.bogus', 'buzz').should == nil
|
@client.discovered_method('plus.bogus', 'plus').should == nil
|
||||||
end
|
|
||||||
|
|
||||||
it 'should fail for string RPC names that do not match API name' do
|
|
||||||
(lambda do
|
|
||||||
@client.generate_request(
|
|
||||||
:api_method => 'chili.activities.list',
|
|
||||||
:parameters => {'alt' => 'json'},
|
|
||||||
:authenticated => false
|
|
||||||
)
|
|
||||||
end).should raise_error(Google::APIClient::TransmissionError)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'should generate requests against the correct URIs' do
|
it 'should generate requests against the correct URIs' do
|
||||||
request = @client.generate_request(
|
request = @client.generate_request(
|
||||||
:api_method => @buzz.activities.list,
|
:api_method => @plus.activities.list,
|
||||||
:parameters => {'userId' => 'hikingfan', 'scope' => '@public'},
|
:parameters => {
|
||||||
|
'userId' => '107807692475771887386', 'collection' => 'public'
|
||||||
|
},
|
||||||
:authenticated => false
|
:authenticated => false
|
||||||
)
|
)
|
||||||
method, uri, headers, body = request
|
method, uri, headers, body = request
|
||||||
uri.should ==
|
uri.should == (
|
||||||
'https://www.googleapis.com/buzz/v1/activities/hikingfan/@public'
|
'https://www.googleapis.com/plus/v1/' +
|
||||||
|
'people/107807692475771887386/activities/public'
|
||||||
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'should correctly validate parameters' do
|
it 'should correctly validate parameters' do
|
||||||
(lambda do
|
(lambda do
|
||||||
@client.generate_request(
|
@client.generate_request(
|
||||||
:api_method => @buzz.activities.list,
|
:api_method => @plus.activities.list,
|
||||||
:parameters => {'alt' => 'json'},
|
:parameters => {'alt' => 'json'},
|
||||||
:authenticated => false
|
:authenticated => false
|
||||||
)
|
)
|
||||||
|
@ -360,33 +354,14 @@ describe Google::APIClient do
|
||||||
it 'should correctly validate parameters' do
|
it 'should correctly validate parameters' do
|
||||||
(lambda do
|
(lambda do
|
||||||
@client.generate_request(
|
@client.generate_request(
|
||||||
:api_method => @buzz.activities.list,
|
:api_method => @plus.activities.list,
|
||||||
:parameters => {'userId' => 'hikingfan', 'scope' => '@bogus'},
|
:parameters => {
|
||||||
|
'userId' => '107807692475771887386', 'collection' => 'bogus'
|
||||||
|
},
|
||||||
:authenticated => false
|
:authenticated => false
|
||||||
)
|
)
|
||||||
end).should raise_error(ArgumentError)
|
end).should raise_error(ArgumentError)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'should be able to execute requests without authorization' do
|
|
||||||
result = @client.execute(
|
|
||||||
@buzz.activities.list,
|
|
||||||
{'alt' => 'json', 'userId' => 'hikingfan', 'scope' => '@public'},
|
|
||||||
'',
|
|
||||||
[],
|
|
||||||
:authenticated => false
|
|
||||||
)
|
|
||||||
status, headers, body = result.response
|
|
||||||
status.should == 200
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'should not be able to execute requests without authorization' do
|
|
||||||
result = @client.execute(
|
|
||||||
@buzz.activities.list,
|
|
||||||
'alt' => 'json', 'userId' => '@me', 'scope' => '@self'
|
|
||||||
)
|
|
||||||
status, headers, body = result.response
|
|
||||||
status.should == 401
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
describe 'with the latitude API' do
|
describe 'with the latitude API' do
|
||||||
|
|
|
@ -24,6 +24,7 @@ namespace :gem do
|
||||||
s.add_runtime_dependency('signet', '~> 0.2.2')
|
s.add_runtime_dependency('signet', '~> 0.2.2')
|
||||||
s.add_runtime_dependency('addressable', '~> 2.2.2')
|
s.add_runtime_dependency('addressable', '~> 2.2.2')
|
||||||
s.add_runtime_dependency('httpadapter', '~> 1.0.0')
|
s.add_runtime_dependency('httpadapter', '~> 1.0.0')
|
||||||
|
s.add_runtime_dependency('autoparse', '~> 0.2.0')
|
||||||
s.add_runtime_dependency('json', '>= 1.4.6')
|
s.add_runtime_dependency('json', '>= 1.4.6')
|
||||||
s.add_runtime_dependency('extlib', '>= 0.9.15')
|
s.add_runtime_dependency('extlib', '>= 0.9.15')
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue