Initial version of new programming interface

This commit is contained in:
Sergio Gomes committed 2013-09-10 15:29:36 +01:00
1 parent 2a3965d976
commit e73ce124fa
6 files changed
+1019

No files matched your search

+150
View File
@@ -0,0 +1,150 @@
# Copyright 2013 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 'google/api_client'
require 'google/api_client/service/stub_generator'
require 'google/api_client/service/resource'
require 'google/api_client/service/request'
require 'google/api_client/service/result'
module Google
class APIClient
##
# Experimental new programming interface at the API level.
# Hides Google::APIClient. Designed to be easier to use, with less code.
#
# @example
# calendar = Google::APIClient::Service.new('calendar', 'v3')
# result = calendar.events.list('calendarId' => 'primary').execute()
class Service
include Google::APIClient::Service::StubGenerator
##
# Creates a new Service.
#
# @param [String, Symbol] api_name
# The name of the API this service will access.
# @param [String, Symbol] api_version
# The version of the API this service will access.
# @param [Hash] options
# The configuration parameters for the service.
# @option options [Symbol, #generate_authenticated_request] :authorization
# (:oauth_1)
# The authorization mechanism used by the client. The following
# mechanisms are supported out-of-the-box:
# <ul>
# <li><code>:two_legged_oauth_1</code></li>
# <li><code>:oauth_1</code></li>
# <li><code>:oauth_2</code></li>
# </ul>
# @option options [Boolean] :auto_refresh_token (true)
# The setting that controls whether or not the api client attempts to
# refresh authorization when a 401 is hit in #execute. If the token does
# not support it, this option is ignored.
# @option options [String] :application_name
# The name of the application using the client.
# @option options [String] :application_version
# The version number of the application using the client.
# @option options [String] :host ("www.googleapis.com")
# The API hostname used by the client. This rarely needs to be changed.
# @option options [String] :port (443)
# The port number used by the client. This rarely needs to be changed.
# @option options [String] :discovery_path ("/discovery/v1")
# The discovery base path. This rarely needs to be changed.
# @option options [String] :ca_file
# Optional set of root certificates to use when validating SSL connections.
# By default, a bundled set of trusted roots will be used.
# @option options [#generate_authenticated_request] :authorization
# The authorization mechanism for requests. Used only if
# `:authenticated` is `true`.
# @option options [TrueClass, FalseClass] :authenticated (default: true)
# `true` if requests must be signed or somehow
# authenticated, `false` otherwise.
# @option options [TrueClass, FalseClass] :gzip (default: true)
# `true` if gzip enabled, `false` otherwise.
# @option options [Faraday] :connection
# A custom connection to be used for all requests.
def initialize(api_name, api_version, options = {})
@api_name = api_name.to_s
if api_version.nil?
raise ArgumentError,
"API version must be set"
end
@api_version = api_version.to_s
if options && !options.respond_to?(:to_hash)
raise ArgumentError,
"expected options Hash, got #{options.class}"
end
params = {}
[:application_name, :application_version, :authorization, :host, :port,
:discovery_path, :auto_refresh_token, :key, :user_ip,
:ca_file].each do |option|
if options.include? option
params[option] = options[option]
end
end
@client = Google::APIClient.new(params)
@options = options
@api = @client.discovered_api(api_name, api_version)
generate_call_stubs(self, @api)
end
##
# Logger for the Service.
#
# @return [Logger] logger instance.
def logger
@client.logger
end
##
# Set the Logger for the Service.
def logger=(obj)
@client.logger = obj
end
##
# Executes an API request.
# Do not call directly; this method is only used by Request objects when
# executing.
# @param [Google::APIClient::Service::Request] request
# The request to be executed.
def execute(request)
params = {:api_method => request.method,
:parameters => request.parameters}
if request.respond_to? :body
if request.body.respond_to? :to_hash
params[:body_object] = request.body
else
params[:body] = request.body
end
end
if request.respond_to? :media
params[:media] = request.media
end
[:connection, :authenticated, :gzip].each do |option|
if @options.include? option
params[option] = @options[option]
end
end
result = @client.execute(params)
return Google::APIClient::Result.new(request, result)
end
end
end
end
+144
View File
@@ -0,0 +1,144 @@
# Copyright 2013 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.
module Google
class APIClient
class Service
##
# Handles an API request.
# This contains a full definition of the request to be made (including
# method name, parameters, body and media). The remote API call can be
# invoked with execute().
class Request
##
# Build a request.
# This class should not be directly instantiated in user code;
# instantiation is handled by the stub methods created on Service and
# Resource objects.
#
# @param [Google::APIClient::Service] service
# The parent Service instance that will execute the request.
# @param [Google::APIClient::Method] method
# The Method instance that describes the API method invoked by the
# request.
# @param [Hash] parameters
# A Hash of parameter names and values to be sent in the API call.
def initialize(service, method, parameters)
@service = service
@method = method
@parameters = parameters
@body = nil
@media = nil
metaclass = (class << self; self; end)
# If applicable, add "body", "body=" and resource-named methods for
# retrieving and setting the HTTP body for this request.
# Examples of setting the body for files.insert in the Drive API:
# request.body = object
# request.execute
# OR
# request.file = object
# request.execute
# OR
# request.body(object).execute
# OR
# request.file(object).execute
# Examples of retrieving the body for files.insert in the Drive API:
# object = request.body
# OR
# object = request.file
if method.request_schema
body_name = method.request_schema.data['id'].dup
body_name[0] = body_name[0].chr.downcase
body_name_equals = (body_name + '=').to_sym
body_name = body_name.to_sym
metaclass.send(:define_method, :body) do |*args|
if args.length == 1
@body = args.first
return self
elsif args.length == 0
return @body
else
raise ArgumentError,
"wrong number of arguments (#{args.length}; expecting 0 or 1)"
end
end
metaclass.send(:define_method, :body=) do |body|
@body = body
end
metaclass.send(:alias_method, body_name, :body)
metaclass.send(:alias_method, body_name_equals, :body=)
end
# If applicable, add "media" and "media=" for retrieving and setting
# the media object for this request.
# Examples of setting the media object:
# request.media = object
# request.execute
# OR
# request.media(object).execute
# Example of retrieving the media object:
# object = request.media
if method.media_upload
metaclass.send(:define_method, :media) do |*args|
if args.length == 1
@media = args.first
return self
elsif args.length == 0
return @media
else
raise ArgumentError,
"wrong number of arguments (#{args.length}; expecting 0 or 1)"
end
end
metaclass.send(:define_method, :media=) do |media|
@media = media
end
end
end
##
# Returns the parent service capable of executing this request.
#
# @return [Google::APIClient::Service] The parent service.
attr_reader :service
##
# Returns the Method instance that describes the API method invoked by
# the request.
#
# @return [Google::APIClient::Method] The API method description.
attr_reader :method
##
# Contains the Hash of parameter names and values to be sent as the
# parameters for the API call.
#
# @return [Hash] The request parameters.
attr_accessor :parameters
##
# Executes the request.
def execute
@service.execute(self)
end
end
end
end
end
+40
View File
@@ -0,0 +1,40 @@
# Copyright 2013 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.
module Google
class APIClient
class Service
##
# Handles an API resource.
# Simple class that contains API methods and/or child resources.
class Resource
include Google::APIClient::Service::StubGenerator
##
# Build a resource.
# This class should not be directly instantiated in user code; resources
# are instantiated by the stub generation mechanism on Service creation.
#
# @param [Google::APIClient::Service] service
# The Service instance this resource belongs to.
# @param [Google::APIClient::API, Google::APIClient::Resource] root
# The node corresponding to this resource.
def initialize(service, root)
@service = service
generate_call_stubs(service, root)
end
end
end
end
end
+162
View File
@@ -0,0 +1,162 @@
# Copyright 2013 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.
module Google
class APIClient
class Service
##
# Handles an API result.
# Wraps around the Google::APIClient::Result class, making it easier to
# handle the result (e.g. pagination) and keeping it in line with the rest
# of the Service programming interface.
class Result
extend Forwardable
##
# Init the result.
#
# @param [Google::APIClient::Service::Request] request
# The original request
# @param [Google::APIClient::Result] base_result
# The base result to be wrapped
def initialize(request, base_result)
@request = request
@base_result = base_result
end
# @!attribute [r] status
# @return [Fixnum] HTTP status code
# @!attribute [r] headers
# @return [Hash] HTTP response headers
# @!attribute [r] body
# @return [String] HTTP response body
def_delegators :@base_result, :status, :headers, :body
# @return [Google::APIClient::Service::Request] Original request object
attr_reader :request
##
# Get the content type of the response
# @!attribute [r] media_type
# @return [String]
# Value of content-type header
def_delegators :@base_result, :media_type
##
# Check if request failed
#
# @!attribute [r] error?
# @return [TrueClass, FalseClass]
# true if result of operation is an error
def_delegators :@base_result, :error?
##
# Check if request was successful
#
# @!attribute [r] success?
# @return [TrueClass, FalseClass]
# true if result of operation was successful
def_delegators :@base_result, :success?
##
# Extracts error messages from the response body
#
# @!attribute [r] error_message
# @return [String]
# error message, if available
def_delegators :@base_result, :error_message
##
# Check for parsable data in response
#
# @!attribute [r] data?
# @return [TrueClass, FalseClass]
# true if body can be parsed
def_delegators :@base_result, :data?
##
# Return parsed version of the response body.
#
# @!attribute [r] data
# @return [Object, Hash, String]
# Object if body parsable from API schema, Hash if JSON, raw body if unable to parse
def_delegators :@base_result, :data
##
# Pagination scheme used by this request/response
#
# @!attribute [r] pagination_type
# @return [Symbol]
# currently always :token
def_delegators :@base_result, :pagination_type
##
# Name of the field that contains the pagination token
#
# @!attribute [r] page_token_param
# @return [String]
# currently always 'pageToken'
def_delegators :@base_result, :page_token_param
##
# Get the token used for requesting the next page of data
#
# @!attribute [r] next_page_token
# @return [String]
# next page tokenx =
def_delegators :@base_result, :next_page_token
##
# Get the token used for requesting the previous page of data
#
# @!attribute [r] prev_page_token
# @return [String]
# previous page token
def_delegators :@base_result, :prev_page_token
# @!attribute [r] resumable_upload
def resumable_upload
# TODO(sgomes): implement resumable_upload for Service::Result
raise NotImplementedError
end
##
# Build a request for fetching the next page of data
#
# @return [Google::APIClient::Service::Request]
# API request for retrieving next page
def next_page
request = @request.clone
# Make a deep copy of the parameters.
request.parameters = Marshal.load(Marshal.dump(request.parameters))
request.parameters[page_token_param] = self.next_page_token
return request
end
##
# Build a request for fetching the previous page of data
#
# @return [Google::APIClient::Service::Request]
# API request for retrieving previous page
def prev_page
request = @request.clone
# Make a deep copy of the parameters.
request.parameters = Marshal.load(Marshal.dump(request.parameters))
request.parameters[page_token_param] = self.prev_page_token
return request
end
end
end
end
end
+59
View File
@@ -0,0 +1,59 @@
# Copyright 2013 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.
module Google
class APIClient
class Service
##
# Auxiliary mixin to generate resource and method stubs.
# Used by the Service and Service::Resource classes to generate both
# top-level and nested resources and methods.
module StubGenerator
def generate_call_stubs(service, root)
metaclass = (class << self; self; end)
# Handle resources.
root.discovered_resources.each do |resource|
method_name = Google::INFLECTOR.underscore(resource.name).to_sym
if !self.respond_to?(method_name)
metaclass.send(:define_method, method_name) do
Google::APIClient::Service::Resource.new(service, resource)
end
end
end
# Handle methods.
root.discovered_methods.each do |method|
method_name = Google::INFLECTOR.underscore(method.name).to_sym
if !self.respond_to?(method_name)
metaclass.send(:define_method, method_name) do |*args|
if args.length > 1
raise ArgumentError,
"wrong number of arguments (#{args.length} for 1)"
elsif !args.first.respond_to?(:to_hash) && !args.first.nil?
raise ArgumentError,
"expected parameter Hash, got #{args.first.class}"
else
return Google::APIClient::Service::Request.new(
service, method, args.first
)
end
end
end
end
end
end
end
end
end