Added support for API feature lists.
[arvados.git] / lib / google / api_client / discovery / api.rb
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 require 'addressable/uri'
17
18 require 'google/inflection'
19 require 'google/api_client/discovery/resource'
20 require 'google/api_client/discovery/method'
21
22 module Google
23   class APIClient
24     ##
25     # A service that has been described by a discovery document.
26     class API
27
28       ##
29       # Creates a description of a particular version of a service.
30       #
31       # @param [String] api
32       #   The identifier for the service.  Note that while this frequently
33       #   matches the first segment of all of the service's RPC names, this
34       #   should not be assumed.  There is no requirement that these match.
35       # @param [String] version
36       #   The identifier for the service version.
37       # @param [Hash] api_description
38       #   The section of the discovery document that applies to this service
39       #   version.
40       #
41       # @return [Google::APIClient::API] The constructed service object.
42       def initialize(document_base, discovery_document)
43         @document_base = Addressable::URI.parse(document_base)
44         @discovery_document = discovery_document
45         metaclass = (class <<self; self; end)
46         self.resources.each do |resource|
47           method_name = Google::INFLECTOR.underscore(resource.name).to_sym
48           if !self.respond_to?(method_name)
49             metaclass.send(:define_method, method_name) { resource }
50           end
51         end
52         self.methods.each do |method|
53           method_name = Google::INFLECTOR.underscore(method.name).to_sym
54           if !self.respond_to?(method_name)
55             metaclass.send(:define_method, method_name) { method }
56           end
57         end
58       end
59
60       ##
61       # Returns the id of the service.
62       #
63       # @return [String] The service id.
64       def id
65         return @discovery_document['id']
66       end
67
68       ##
69       # Returns the identifier for the service.
70       #
71       # @return [String] The service identifier.
72       def name
73         return @discovery_document['name']
74       end
75
76       ##
77       # Returns the version of the service.
78       #
79       # @return [String] The service version.
80       def version
81         return @discovery_document['version']
82       end
83
84       ##
85       # Returns the parsed section of the discovery document that applies to
86       # this version of the service.
87       #
88       # @return [Hash] The service description.
89       def description
90         return @discovery_document['description']
91       end
92
93       ##
94       # Returns true if this is the preferred version of this API.
95       #
96       # @return [TrueClass, FalseClass]
97       #   Whether or not this is the preferred version of this API.
98       def preferred
99         return !!@discovery_document['preferred']
100       end
101
102       ##
103       # Returns the list of API features.
104       #
105       # @return [Array]
106       #   The features supported by this API.
107       def features
108         return @discovery_document['features'] || []
109       end
110
111       ##
112       # Returns true if this API uses a data wrapper.
113       #
114       # @return [TrueClass, FalseClass]
115       #   Whether or not this API uses a data wrapper.
116       def data_wrapper?
117         return self.features.include?('dataWrapper')
118       end
119
120       ##
121       # Returns the base URI for the discovery document.
122       #
123       # @return [Addressable::URI] The base URI.
124       attr_reader :document_base
125
126       ##
127       # Returns the base URI for this version of the service.
128       #
129       # @return [Addressable::URI] The base URI that methods are joined to.
130       def method_base
131         if @discovery_document['basePath']
132           return @method_base ||= (
133             self.document_base +
134             Addressable::URI.parse(@discovery_document['basePath'])
135           ).normalize
136         else
137           return nil
138         end
139       end
140
141       ##
142       # Updates the hierarchy of resources and methods with the new base.
143       #
144       # @param [Addressable::URI, #to_str, String] new_base
145       #   The new base URI to use for the service.
146       def method_base=(new_method_base)
147         @method_base = Addressable::URI.parse(new_method_base)
148         self.resources.each do |resource|
149           resource.method_base = @method_base
150         end
151         self.methods.each do |method|
152           method.method_base = @method_base
153         end
154       end
155
156       ##
157       # A list of schemas available for this version of the API.
158       #
159       # @return [Hash] A list of {Google::APIClient::Schema} objects.
160       def schemas
161         return @schemas ||= (
162           (@discovery_document['schemas'] || []).inject({}) do |accu, (k, v)|
163             accu[k] = Google::APIClient::Schema.new(
164               self, self.name, self.version, v
165             )
166             accu
167           end
168         )
169       end
170
171       ##
172       # Returns a schema for a kind value.
173       #
174       # @return [Google::APIClient::Schema] The associated Schema object.
175       def schema_for_kind(kind)
176         api_name, schema_name = kind.split('#', 2)
177         if api_name != self.name
178           raise ArgumentError,
179             "The kind does not match this API. " +
180             "Expected '#{self.name}', got '#{api_name}'."
181         end
182         for k, v in self.schemas
183           return v if k.downcase == schema_name.downcase
184         end
185         return nil
186       end
187
188       ##
189       # A list of resources available at the root level of this version of the
190       # API.
191       #
192       # @return [Array] A list of {Google::APIClient::Resource} objects.
193       def resources
194         return @resources ||= (
195           (@discovery_document['resources'] || []).inject([]) do |accu, (k, v)|
196             accu << Google::APIClient::Resource.new(
197               self, self.method_base, k, v
198             )
199             accu
200           end
201         )
202       end
203
204       ##
205       # A list of methods available at the root level of this version of the
206       # API.
207       #
208       # @return [Array] A list of {Google::APIClient::Method} objects.
209       def methods
210         return @methods ||= (
211           (@discovery_document['methods'] || []).inject([]) do |accu, (k, v)|
212             accu << Google::APIClient::Method.new(self, self.method_base, k, v)
213             accu
214           end
215         )
216       end
217
218       ##
219       # Converts the service to a flat mapping of RPC names and method objects.
220       #
221       # @return [Hash] All methods available on the service.
222       #
223       # @example
224       #   # Discover available methods
225       #   method_names = client.discovered_api('buzz').to_h.keys
226       def to_h
227         return @hash ||= (begin
228           methods_hash = {}
229           self.methods.each do |method|
230             methods_hash[method.id] = method
231           end
232           self.resources.each do |resource|
233             methods_hash.merge!(resource.to_h)
234           end
235           methods_hash
236         end)
237       end
238
239       ##
240       # Returns a <code>String</code> representation of the service's state.
241       #
242       # @return [String] The service's state, as a <code>String</code>.
243       def inspect
244         sprintf(
245           "#<%s:%#0x ID:%s>", self.class.to_s, self.object_id, self.id
246         )
247       end
248     end
249   end
250 end