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
75 return content_type[/^([^;]*);?.*$/, 1].strip.downcase
82 # Check if request failed
84 # @!attribute [r] error?
85 # @return [TrueClass, FalseClass]
86 # true if result of operation is an error
88 return self.response.status >= 400
92 # Check if request was successful
94 # @!attribute [r] success?
95 # @return [TrueClass, FalseClass]
96 # true if result of operation was successful
102 # Extracts error messages from the response body
104 # @!attribute [r] error_message
106 # error message, if available
109 if self.data.respond_to?(:error) &&
110 self.data.error.respond_to?(:message)
111 # You're going to get a terrible error message if the response isn't
112 # parsed successfully as an error.
113 return self.data.error.message
114 elsif self.data['error'] && self.data['error']['message']
115 return self.data['error']['message']
122 # Check for parsable data in response
124 # @!attribute [r] data?
125 # @return [TrueClass, FalseClass]
126 # true if body can be parsed
128 !(self.body.nil? || self.body.empty? || self.media_type != 'application/json')
132 # Return parsed version of the response body.
134 # @!attribute [r] data
135 # @return [Object, Hash, String]
136 # Object if body parsable from API schema, Hash if JSON, raw body if unable to parse
138 return @data ||= (begin
140 media_type = self.media_type
143 when 'application/json'
144 data = MultiJson.load(data)
145 # Strip data wrapper, if present
146 data = data['data'] if data.has_key?('data')
149 "Content-Type not supported for parsing: #{media_type}"
151 if @request.api_method && @request.api_method.response_schema
152 # Automatically parse using the schema designated for the
153 # response of this API method.
154 data = @request.api_method.response_schema.new(data)
157 # Otherwise, return the raw unparsed value.
158 # This value must be indexable like a Hash.
166 # Get the token used for requesting the next page of data
168 # @!attribute [r] next_page_token
172 if self.data.respond_to?(:next_page_token)
173 return self.data.next_page_token
174 elsif self.data.respond_to?(:[])
175 return self.data["nextPageToken"]
177 raise TypeError, "Data object did not respond to #next_page_token."
182 # Build a request for fetching the next page of data
184 # @return [Google::APIClient::Request]
185 # API request for retrieving next page
187 merged_parameters = Hash[self.reference.parameters].merge({
188 self.page_token_param => self.next_page_token
190 # Because Requests can be coerced to Hashes, we can merge them,
191 # preserving all context except the API method parameters that we're
192 # using for pagination.
193 return Google::APIClient::Request.new(
194 Hash[self.reference].merge(:parameters => merged_parameters)
199 # Get the token used for requesting the previous page of data
201 # @!attribute [r] prev_page_token
203 # previous page token
205 if self.data.respond_to?(:prev_page_token)
206 return self.data.prev_page_token
207 elsif self.data.respond_to?(:[])
208 return self.data["prevPageToken"]
210 raise TypeError, "Data object did not respond to #next_page_token."
215 # Build a request for fetching the previous page of data
217 # @return [Google::APIClient::Request]
218 # API request for retrieving previous page
220 merged_parameters = Hash[self.reference.parameters].merge({
221 self.page_token_param => self.prev_page_token
223 # Because Requests can be coerced to Hashes, we can merge them,
224 # preserving all context except the API method parameters that we're
225 # using for pagination.
226 return Google::APIClient::Request.new(
227 Hash[self.reference].merge(:parameters => merged_parameters)
232 # Pagination scheme used by this request/response
234 # @!attribute [r] pagination_type
236 # currently always :token
242 # Name of the field that contains the pagination token
244 # @!attribute [r] page_token_param
246 # currently always 'pageToken'