module Totter module Transport # Default HTTP API transport adapter module HTTP require 'net/http' require 'net/https' require 'uri' require 'multi_json' require 'hashie' private def http return @http if @http uri = URI.parse(self.base_url) @http = Net::HTTP.new(uri.host, uri.port) @http.use_ssl = self.ssl? @http end def request(method, path, params = nil) uri = URI.parse("#{self.base_url}#{path}") # if the request requires parameters in the query string, merge them in if params and !can_post_data?(method) query_values = uri.query ? URI.decode_www_form(uri.query).inject({}) {|h,(k,v)| h[k]=v; h} : {} uri.query = URI.encode_www_form (query_values || {}).merge(params) end # Build request request = build_request(method, uri) # Add headers request['Authorization'] = "Bearer #{self.access_token}" if authenticated? request['X-Seesaw-Client-Token'] = @client_token if @client_token request['Content-Type'] = 'application/json' # Add params as JSON if they exist request.body = MultiJson.dump(params) if can_post_data?(method) and params # Request response = http.request(request) # Check for errors handle_error(response) # Return the raw response object response end def build_request(method, uri) case method when :get Net::HTTP::Get.new(uri.request_uri) when :post Net::HTTP::Post.new(uri.request_uri) when :put Net::HTTP::Put.new(uri.request_uri) when :delete Net::HTTP::Delete.new(uri.request_uri) end end def handle_error(response) # Find error or return return unless error = Totter::ERROR_MAP[response.code.to_i] # Try to add a useful message message = nil begin message = MultiJson.load(response.body)['error_description'] rescue MultiJson::DecodeError => e end # Raise error raise error.new(message) end def json_request(*args) return Response.new(Hashie::Mash.new(body: {}.to_json, headers: [])) if Totter::Client.stubbed? # Perform request Response.new(request(*args)) end def boolean_from_response(*args) response = request(*args) (200..299).include? response.code.to_i end def can_post_data?(method) [:post, :put].include?(method) end [:get, :post, :put, :delete].each do |method| define_method method do |*args| json_request(method, *args) end end class Response attr_accessor :body, :headers def initialize(http_response) @headers = parse_headers(http_response.to_hash) @body = parse_body(http_response.body) end private def parse_headers(raw_headers) raw_headers.inject({}) do |remainder, (k, v)| remainder[k] = [v].flatten.first remainder end end def parse_body(body) # Parse JSON object = MultiJson.load(body) # Hash return Hashie::Mash.new(object) if object.is_a? Hash # Array begin return object.map { |h| Hashie::Mash.new(h) } if object.is_a? Array rescue # sometimes, for things like string arrays, we'll end up with an error end # Fallback incase it's not a hash or array object end end end end end