1 # Copyright 2010 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.
19 # This class wraps a result returned by an API call.
26 # @param [Google::APIClient::Request] request
27 # The original request
28 # @param [Faraday::Response] response
30 def initialize(request, response)
33 @media_upload = reference if reference.kind_of?(ResumableUpload)
36 # @return [Google::APIClient::Request] Original request object
38 # @return [Faraday::Response] HTTP response
40 # @!attribute [r] reference
41 # @return [Google::APIClient::Request] Original request object
42 # @deprecated See {#request}
43 alias_method :reference, :request # For compatibility with pre-beta clients
45 # @!attribute [r] status
46 # @return [Fixnum] HTTP status code
47 # @!attribute [r] headers
48 # @return [Hash] HTTP response headers
49 # @!attribute [r] body
50 # @return [String] HTTP response body
51 def_delegators :@response, :status, :headers, :body
53 # @!attribute [r] resumable_upload
54 # @return [Google::APIClient::ResumableUpload] For resuming media uploads
57 options = self.reference.to_hash.merge(
58 :uri => self.headers['location'],
59 :media => self.reference.media
61 Google::APIClient::ResumableUpload.new(options)
66 # Get the content type of the response
67 # @!attribute [r] media_type
69 # Value of content-type header
71 _, content_type = self.headers.detect do |h, v|
72 h.downcase == 'Content-Type'.downcase
74 content_type[/^([^;]*);?.*$/, 1].strip.downcase
78 # Check if request failed
80 # @!attribute [r] error?
81 # @return [TrueClass, FalseClass]
82 # true if result of operation is an error
84 return self.response.status >= 400
88 # Check if request was successful
90 # @!attribute [r] success?
91 # @return [TrueClass, FalseClass]
92 # true if result of operation was successful
98 # Extracts error messages from the response body
100 # @!attribute [r] error_message
102 # error message, if available
105 if self.data.respond_to?(:error) &&
106 self.data.error.respond_to?(:message)
107 # You're going to get a terrible error message if the response isn't
108 # parsed successfully as an error.
109 return self.data.error.message
110 elsif self.data['error'] && self.data['error']['message']
111 return self.data['error']['message']
118 # Check for parsable data in response
120 # @!attribute [r] data?
121 # @return [TrueClass, FalseClass]
122 # true if body can be parsed
124 self.media_type == 'application/json'
128 # Return parsed version of the response body.
130 # @!attribute [r] data
131 # @return [Object, Hash, String]
132 # Object if body parsable from API schema, Hash if JSON, raw body if unable to parse
134 return @data ||= (begin
135 media_type = self.media_type
138 when 'application/json'
139 data = MultiJson.load(data)
140 # Strip data wrapper, if present
141 data = data['data'] if data.has_key?('data')
144 "Content-Type not supported for parsing: #{media_type}"
146 if @request.api_method && @request.api_method.response_schema
147 # Automatically parse using the schema designated for the
148 # response of this API method.
149 data = @request.api_method.response_schema.new(data)
152 # Otherwise, return the raw unparsed value.
153 # This value must be indexable like a Hash.
160 # Get the token used for requesting the next page of data
162 # @!attribute [r] next_page_token
166 if self.data.respond_to?(:next_page_token)
167 return self.data.next_page_token
168 elsif self.data.respond_to?(:[])
169 return self.data["nextPageToken"]
171 raise TypeError, "Data object did not respond to #next_page_token."
176 # Build a request for fetching the next page of data
178 # @return [Google::APIClient::Request]
179 # API request for retrieving next page
181 merged_parameters = Hash[self.reference.parameters].merge({
182 self.page_token_param => self.next_page_token
184 # Because Requests can be coerced to Hashes, we can merge them,
185 # preserving all context except the API method parameters that we're
186 # using for pagination.
187 return Google::APIClient::Request.new(
188 Hash[self.reference].merge(:parameters => merged_parameters)
193 # Get the token used for requesting the previous page of data
195 # @!attribute [r] prev_page_token
197 # previous page token
199 if self.data.respond_to?(:prev_page_token)
200 return self.data.prev_page_token
201 elsif self.data.respond_to?(:[])
202 return self.data["prevPageToken"]
204 raise TypeError, "Data object did not respond to #next_page_token."
209 # Build a request for fetching the previous page of data
211 # @return [Google::APIClient::Request]
212 # API request for retrieving previous page
214 merged_parameters = Hash[self.reference.parameters].merge({
215 self.page_token_param => self.prev_page_token
217 # Because Requests can be coerced to Hashes, we can merge them,
218 # preserving all context except the API method parameters that we're
219 # using for pagination.
220 return Google::APIClient::Request.new(
221 Hash[self.reference].merge(:parameters => merged_parameters)
226 # Pagination scheme used by this request/response
228 # @!attribute [r] pagination_type
230 # currently always :token
236 # Name of the field that contains the pagination token
238 # @!attribute [r] page_token_param
240 # currently always 'pageToken'