More documentation cleanup
[arvados.git] / lib / google / api_client / result.rb
index 72c3968814111c1c24d997911f64b98c418b8c1d..8920f942137eba9864db6d0099a492a2e570c4ad 100644 (file)
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+
 module Google
   class APIClient
     ##
     # This class wraps a result returned by an API call.
     class Result
-      def initialize(reference, request, response)
-        @reference = reference
+      extend Forwardable
+      
+      ##
+      # Init the result
+      #
+      # @param [Google::APIClient::Request] request
+      #   The original request
+      # @param [Faraday::Response] response
+      #   Raw HTTP Response
+      def initialize(request, response)
         @request = request
         @response = response
+        @media_upload = reference if reference.kind_of?(ResumableUpload)
       end
 
-      attr_reader :reference
-
+      # @return [Google::APIClient::Request] Original request object
       attr_reader :request
-
+      # @return [Faraday::Response] HTTP response
       attr_reader :response
+      # @!attribute [r] reference
+      #   @return [Google::APIClient::Request] Original request object
+      #   @deprecated See {#request}
+      alias_method :reference, :request # For compatibility with pre-beta clients
 
-      def status
-        return @response[0]
-      end
+      # @!attribute [r] status
+      #   @return [Fixnum] HTTP status code
+      # @!attribute [r] headers
+      #   @return [Hash] HTTP response headers
+      # @!attribute [r] body
+      #   @return [String] HTTP response body
+      def_delegators :@response, :status, :headers, :body
 
-      def headers
-        return @response[1]
+      # @!attribute [r] resumable_upload
+      # @return [Google::APIClient::ResumableUpload] For resuming media uploads
+      def resumable_upload        
+        @media_upload ||= (
+          options = self.reference.to_hash.merge(
+            :uri => self.headers['location'],
+            :media => self.reference.media
+          )
+          Google::APIClient::ResumableUpload.new(options)
+        )
+      end
+      
+      ##
+      # Get the content type of the response
+      # @!attribute [r] media_type
+      # @return [String]
+      #  Value of content-type header
+      def media_type
+        _, content_type = self.headers.detect do |h, v|
+          h.downcase == 'Content-Type'.downcase
+        end
+        content_type[/^([^;]*);?.*$/, 1].strip.downcase
+      end
+      
+      ##
+      # Check if request failed
+      #
+      # @!attribute [r] error?
+      # @return [TrueClass, FalseClass]
+      #   true if result of operation is an error
+      def error?
+        return self.response.status >= 400
       end
 
-      def body
-        return @body ||= (begin
-          response_body = @response[2]
-          merged_body = (response_body.inject(StringIO.new) do |accu, chunk|
-            accu.write(chunk)
-            accu
-          end).string
-        end)
+      ##
+      # Check if request was successful
+      #
+      # @!attribute [r] success?
+      # @return [TrueClass, FalseClass]
+      #   true if result of operation was successful
+      def success?
+        return !self.error?
+      end
+      
+      ##
+      # Extracts error messages from the response body
+      #
+      # @!attribute [r] error_message
+      # @return [String]
+      #   error message, if available
+      def error_message
+        if self.data?
+          if self.data.respond_to?(:error) &&
+             self.data.error.respond_to?(:message)
+            # You're going to get a terrible error message if the response isn't
+            # parsed successfully as an error.
+            return self.data.error.message
+          elsif self.data['error'] && self.data['error']['message']
+            return self.data['error']['message']
+          end
+        end
+        return self.body
       end
 
+      ##
+      # Check for parsable data in response
+      #
+      # @!attribute [r] data?
+      # @return [TrueClass, FalseClass]
+      #   true if body can be parsed
+      def data?
+        self.media_type == 'application/json'
+      end
+      
+      ##
+      # Return parsed version of the response body.
+      #
+      # @!attribute [r] data
+      # @return [Object, Hash, String]
+      #   Object if body parsable from API schema, Hash if JSON, raw body if unable to parse
       def data
         return @data ||= (begin
-          _, content_type = self.headers.detect do |h, v|
-            h.downcase == 'Content-Type'.downcase
-          end
-          media_type = content_type[/^([^;]*);?.*$/, 1].strip.downcase
+          media_type = self.media_type
           data = self.body
           case media_type
           when 'application/json'
-            data = ::JSON.parse(data)
+            data = MultiJson.load(data)
             # Strip data wrapper, if present
             data = data['data'] if data.has_key?('data')
           else
             raise ArgumentError,
               "Content-Type not supported for parsing: #{media_type}"
           end
-          if @reference.api_method && @reference.api_method.response_schema
+          if @request.api_method && @request.api_method.response_schema
             # Automatically parse using the schema designated for the
             # response of this API method.
-            data = @reference.api_method.response_schema.new(data)
+            data = @request.api_method.response_schema.new(data)
             data
           else
             # Otherwise, return the raw unparsed value.
@@ -76,14 +156,12 @@ module Google
         end)
       end
 
-      def pagination_type
-        return :token
-      end
-
-      def page_token_param
-        return "pageToken"
-      end
-
+      ##
+      # Get the token used for requesting the next page of data
+      #
+      # @!attribute [r] next_page_token
+      # @return [String]
+      #   next page token
       def next_page_token
         if self.data.respond_to?(:next_page_token)
           return self.data.next_page_token
@@ -94,18 +172,29 @@ module Google
         end
       end
 
+      ##
+      # Build a request for fetching the next page of data
+      # 
+      # @return [Google::APIClient::Request]
+      #   API request for retrieving next page
       def next_page
         merged_parameters = Hash[self.reference.parameters].merge({
           self.page_token_param => self.next_page_token
         })
-        # Because References can be coerced to Hashes, we can merge them,
+        # Because Requests can be coerced to Hashes, we can merge them,
         # preserving all context except the API method parameters that we're
         # using for pagination.
-        return Google::APIClient::Reference.new(
+        return Google::APIClient::Request.new(
           Hash[self.reference].merge(:parameters => merged_parameters)
         )
       end
 
+      ##
+      # Get the token used for requesting the previous page of data
+      #
+      # @!attribute [r] prev_page_token
+      # @return [String]
+      #   previous page token
       def prev_page_token
         if self.data.respond_to?(:prev_page_token)
           return self.data.prev_page_token
@@ -116,17 +205,43 @@ module Google
         end
       end
 
+      ##
+      # Build a request for fetching the previous page of data
+      # 
+      # @return [Google::APIClient::Request]
+      #   API request for retrieving previous page
       def prev_page
         merged_parameters = Hash[self.reference.parameters].merge({
           self.page_token_param => self.prev_page_token
         })
-        # Because References can be coerced to Hashes, we can merge them,
+        # Because Requests can be coerced to Hashes, we can merge them,
         # preserving all context except the API method parameters that we're
         # using for pagination.
-        return Google::APIClient::Reference.new(
+        return Google::APIClient::Request.new(
           Hash[self.reference].merge(:parameters => merged_parameters)
         )
       end
+      
+      ##
+      # Pagination scheme used by this request/response
+      #
+      # @!attribute [r] pagination_type
+      # @return [Symbol]
+      #  currently always :token
+      def pagination_type
+        return :token
+      end
+
+      ##
+      # Name of the field that contains the pagination token
+      #
+      # @!attribute [r] page_token_param
+      # @return [String]
+      #  currently always 'pageToken'
+      def page_token_param
+        return "pageToken"
+      end
+
     end
   end
 end