Migrated to MultiJson from JSON gem.
[arvados.git] / lib / google / api_client / result.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 module Google
17   class APIClient
18     ##
19     # This class wraps a result returned by an API call.
20     class Result
21       def initialize(reference, request, response)
22         @reference = reference
23         @request = request
24         @response = response
25       end
26
27       attr_reader :reference
28
29       attr_reader :request
30
31       attr_reader :response
32
33       def status
34         return @response[0]
35       end
36
37       def headers
38         return @response[1]
39       end
40
41       def body
42         return @body ||= (begin
43           response_body = @response[2]
44           merged_body = (response_body.inject(StringIO.new) do |accu, chunk|
45             accu.write(chunk)
46             accu
47           end).string
48         end)
49       end
50
51       def data
52         return @data ||= (begin
53           _, content_type = self.headers.detect do |h, v|
54             h.downcase == 'Content-Type'.downcase
55           end
56           media_type = content_type[/^([^;]*);?.*$/, 1].strip.downcase
57           data = self.body
58           case media_type
59           when 'application/json'
60             data = MultiJson.decode(data)
61             # Strip data wrapper, if present
62             data = data['data'] if data.has_key?('data')
63           else
64             raise ArgumentError,
65               "Content-Type not supported for parsing: #{media_type}"
66           end
67           if @reference.api_method && @reference.api_method.response_schema
68             # Automatically parse using the schema designated for the
69             # response of this API method.
70             data = @reference.api_method.response_schema.new(data)
71             data
72           else
73             # Otherwise, return the raw unparsed value.
74             # This value must be indexable like a Hash.
75             data
76           end
77         end)
78       end
79
80       def pagination_type
81         return :token
82       end
83
84       def page_token_param
85         return "pageToken"
86       end
87
88       def next_page_token
89         if self.data.respond_to?(:next_page_token)
90           return self.data.next_page_token
91         elsif self.data.respond_to?(:[])
92           return self.data["nextPageToken"]
93         else
94           raise TypeError, "Data object did not respond to #next_page_token."
95         end
96       end
97
98       def next_page
99         merged_parameters = Hash[self.reference.parameters].merge({
100           self.page_token_param => self.next_page_token
101         })
102         # Because References can be coerced to Hashes, we can merge them,
103         # preserving all context except the API method parameters that we're
104         # using for pagination.
105         return Google::APIClient::Reference.new(
106           Hash[self.reference].merge(:parameters => merged_parameters)
107         )
108       end
109
110       def prev_page_token
111         if self.data.respond_to?(:prev_page_token)
112           return self.data.prev_page_token
113         elsif self.data.respond_to?(:[])
114           return self.data["prevPageToken"]
115         else
116           raise TypeError, "Data object did not respond to #next_page_token."
117         end
118       end
119
120       def prev_page
121         merged_parameters = Hash[self.reference.parameters].merge({
122           self.page_token_param => self.prev_page_token
123         })
124         # Because References can be coerced to Hashes, we can merge them,
125         # preserving all context except the API method parameters that we're
126         # using for pagination.
127         return Google::APIClient::Reference.new(
128           Hash[self.reference].merge(:parameters => merged_parameters)
129         )
130       end
131     end
132   end
133 end