1 # Copyright 2013 Google Inc.
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
7 # http://www.apache.org/licenses/LICENSE-2.0
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.
15 require 'google/api_client'
16 require 'google/api_client/service/stub_generator'
17 require 'google/api_client/service/resource'
18 require 'google/api_client/service/request'
19 require 'google/api_client/service/result'
20 require 'google/api_client/service/batch'
21 require 'google/api_client/service/simple_file_store'
27 # Experimental new programming interface at the API level.
28 # Hides Google::APIClient. Designed to be easier to use, with less code.
31 # calendar = Google::APIClient::Service.new('calendar', 'v3')
32 # result = calendar.events.list('calendarId' => 'primary').execute()
34 include Google::APIClient::Service::StubGenerator
37 DEFAULT_CACHE_FILE = 'discovery.cache'
39 # Cache for discovered APIs.
43 # Creates a new Service.
45 # @param [String, Symbol] api_name
46 # The name of the API this service will access.
47 # @param [String, Symbol] api_version
48 # The version of the API this service will access.
49 # @param [Hash] options
50 # The configuration parameters for the service.
51 # @option options [Symbol, #generate_authenticated_request] :authorization
53 # The authorization mechanism used by the client. The following
54 # mechanisms are supported out-of-the-box:
56 # <li><code>:two_legged_oauth_1</code></li>
57 # <li><code>:oauth_1</code></li>
58 # <li><code>:oauth_2</code></li>
60 # @option options [Boolean] :auto_refresh_token (true)
61 # The setting that controls whether or not the api client attempts to
62 # refresh authorization when a 401 is hit in #execute. If the token does
63 # not support it, this option is ignored.
64 # @option options [String] :application_name
65 # The name of the application using the client.
66 # @option options [String] :application_version
67 # The version number of the application using the client.
68 # @option options [String] :host ("www.googleapis.com")
69 # The API hostname used by the client. This rarely needs to be changed.
70 # @option options [String] :port (443)
71 # The port number used by the client. This rarely needs to be changed.
72 # @option options [String] :discovery_path ("/discovery/v1")
73 # The discovery base path. This rarely needs to be changed.
74 # @option options [String] :ca_file
75 # Optional set of root certificates to use when validating SSL connections.
76 # By default, a bundled set of trusted roots will be used.
77 # @option options [#generate_authenticated_request] :authorization
78 # The authorization mechanism for requests. Used only if
79 # `:authenticated` is `true`.
80 # @option options [TrueClass, FalseClass] :authenticated (default: true)
81 # `true` if requests must be signed or somehow
82 # authenticated, `false` otherwise.
83 # @option options [TrueClass, FalseClass] :gzip (default: true)
84 # `true` if gzip enabled, `false` otherwise.
85 # @option options [Faraday::Connection] :connection
86 # A custom connection to be used for all requests.
87 # @option options [ActiveSupport::Cache::Store, :default] :discovery_cache
88 # A cache store to place the discovery documents for loaded APIs.
89 # Avoids unnecessary roundtrips to the discovery service.
90 # :default loads the default local file cache store.
91 def initialize(api_name, api_version, options = {})
92 @api_name = api_name.to_s
95 "API version must be set"
97 @api_version = api_version.to_s
98 if options && !options.respond_to?(:to_hash)
100 "expected options Hash, got #{options.class}"
104 [:application_name, :application_version, :authorization, :host, :port,
105 :discovery_path, :auto_refresh_token, :key, :user_ip,
106 :ca_file].each do |option|
107 if options.include? option
108 params[option] = options[option]
112 @client = Google::APIClient.new(params)
114 @connection = options[:connection] || @client.connection
118 # Initialize cache store. Default to SimpleFileStore if :cache_store
119 # is not provided and we have write permissions.
120 if options.include? :cache_store
121 @cache_store = options[:cache_store]
123 cache_exists = File.exists?(DEFAULT_CACHE_FILE)
124 if (cache_exists && File.writable?(DEFAULT_CACHE_FILE)) ||
125 (!cache_exists && File.writable?(Dir.pwd))
126 @cache_store = Google::APIClient::Service::SimpleFileStore.new(
131 # Attempt to read API definition from memory cache.
132 # Not thread-safe, but the worst that can happen is a cache miss.
133 unless @api = @@discovered[[api_name, api_version]]
134 # Attempt to read API definition from cache store, if there is one.
135 # If there's a miss or no cache store, call discovery service.
136 if !@cache_store.nil?
137 @api = @cache_store.fetch("%s/%s" % [api_name, api_version]) do
138 @client.discovered_api(api_name, api_version)
141 @api = @client.discovered_api(api_name, api_version)
143 @@discovered[[api_name, api_version]] = @api
146 generate_call_stubs(self, @api)
150 # Returns the authorization mechanism used by the service.
152 # @return [#generate_authenticated_request] The authorization mechanism.
153 def_delegators :@client, :authorization, :authorization=
156 # The setting that controls whether or not the service attempts to
157 # refresh authorization when a 401 is hit during an API call.
160 def_delegators :@client, :auto_refresh_token, :auto_refresh_token=
163 # The application's API key issued by the API console.
165 # @return [String] The API key.
166 def_delegators :@client, :key, :key=
169 # The Faraday/HTTP connection used by this service.
171 # @return [Faraday::Connection]
172 attr_accessor :connection
175 # The cache store used for storing discovery documents.
177 # @return [ActiveSupport::Cache::Store,
178 # Google::APIClient::Service::SimpleFileStore,
180 attr_reader :cache_store
183 # Prepares a Google::APIClient::BatchRequest object to make batched calls.
184 # @param [Array] calls
185 # Optional array of Google::APIClient::Service::Request to initialize
186 # the batch request with.
187 # @param [Proc] block
188 # Callback for every call's response. Won't be called if a call defined
189 # a callback of its own.
191 # @yield [Google::APIClient::Service::Result]
192 # block to be called when result ready
193 def batch(calls = nil, &block)
194 Google::APIClient::Service::BatchRequest.new(self, calls, &block)
198 # Executes an API request.
199 # Do not call directly; this method is only used by Request objects when
202 # @param [Google::APIClient::Service::Request,
203 # Google::APIClient::Service::BatchCall] request
204 # The request to be executed.
206 if request.instance_of? Google::APIClient::Service::Request
207 params = {:api_method => request.method,
208 :parameters => request.parameters,
209 :connection => @connection}
210 if request.respond_to? :body
211 if request.body.respond_to? :to_hash
212 params[:body_object] = request.body
214 params[:body] = request.body
217 if request.respond_to? :media
218 params[:media] = request.media
220 [:authenticated, :gzip].each do |option|
221 if @options.include? option
222 params[option] = @options[option]
225 result = @client.execute(params)
226 return Google::APIClient::Service::Result.new(request, result)
227 elsif request.instance_of? Google::APIClient::Service::BatchRequest
228 @client.execute(request.base_batch, {:connection => @connection})