def request(hash, aid = nil)
      http = http_client
      
      uri = @api_uri
      if aid
        uri += "?aid=#{CGI.escape aid}"
      end

      # Mostly for debugging, store these
      @last_request_uri = uri

      start_time = Time.now

      if self.http_method == :post
        @last_request_json = json_request = JSON.generate(hash)        
        http_response = http.post uri, json_request, self.request_headers
      elsif self.http_method == :get
        @last_request_query_params = hash
        http_response = http.get uri, hash, self.request_headers
      else
        raise ArgumentError.new("BorrowDirect::Request only understands http_method :get and :post, not `#{self.http_method}`")
      end

      @last_request_response = http_response
      @last_request_time     = Time.now - start_time

      response_hash = begin
        JSON.parse(http_response.body)
      rescue JSON::ParserError => json_parse_exception
        nil
      end

      # will be nil if we have none
      einfo = error_info(response_hash)
      expected_error = (einfo && self.expected_error_codes.include?(einfo.number))


      if einfo && (! expected_error)
        if BorrowDirect::Error.invalid_aid_code?(einfo.number)
          raise BorrowDirect::InvalidAidError.new(einfo.message, einfo.number, aid)
        else
          raise BorrowDirect::Error.new(einfo.message, einfo.number)      
        end
      elsif http_response.code != 200 && (! expected_error)
        raise BorrowDirect::HttpError.new("HTTP Error: #{http_response.code}: #{http_response.body}")
      elsif response_hash.nil?
        raise BorrowDirect::Error.new("Could not parse expected JSON response: #{http_response.code} #{json_parse_exception}: #{http_response.body}")
      end

      

      return response_hash
    rescue HTTPClient::ReceiveTimeoutError, HTTPClient::ConnectTimeoutError, HTTPClient::SendTimeoutError => e
      elapsed = Time.now - start_time
      raise BorrowDirect::HttpTimeoutError.new("Timeout after #{elapsed.round(1)}s connecting to BorrowDirect server at #{@api_base}", self.timeout)
    end
def request(hash, aid = nil)
      http = http_client
      
      uri = @api_uri
      if aid
        uri += "?aid=#{CGI.escape aid}"
      end

      # Mostly for debugging, store these
      @last_request_uri = uri

      start_time = Time.now

      if self.http_method == :post
        @last_request_json = json_request = JSON.generate(hash)        
        http_response = http.post uri, json_request, self.request_headers
      elsif self.http_method == :get
        @last_request_query_params = hash
        http_response = http.get uri, hash, self.request_headers
      else
        raise ArgumentError.new("BorrowDirect::Request only understands http_method :get and :post, not `#{self.http_method}`")
      end

      @last_request_response = http_response
      @last_request_time     = Time.now - start_time

      response_hash = begin
        JSON.parse(http_response.body)
      rescue JSON::ParserError => json_parse_exception
        nil
      end

      # will be nil if we have none
      einfo = error_info(response_hash)
      expected_error = (einfo && self.expected_error_codes.include?(einfo.number))


      if einfo && (! expected_error)
        if BorrowDirect::Error.invalid_aid_code?(einfo.number)
          raise BorrowDirect::InvalidAidError.new(einfo.message, einfo.number, aid)
        else
          raise BorrowDirect::Error.new(einfo.message, einfo.number)      
        end
      elsif http_response.code != 200 && (! expected_error)
        raise BorrowDirect::HttpError.new("HTTP Error: #{http_response.code}: #{http_response.body}")
      elsif response_hash.nil?
        raise BorrowDirect::Error.new("Could not parse expected JSON response: #{http_response.code} #{json_parse_exception}: #{http_response.body}")
      end

      

      return response_hash
    rescue HTTPClient::ReceiveTimeoutError, HTTPClient::ConnectTimeoutError, HTTPClient::SendTimeoutError => e
      elapsed = Time.now - start_time
      raise BorrowDirect::HttpTimeoutError.new("Timeout after #{elapsed.round(1)}s connecting to BorrowDirect server at #{@api_base}", self.timeout)
    end
First param is request hash, will be query param for GET or JSON body for POST
 Second param is optional AuthenticationID used by BD system -- if given,
 will be added to URI as "?aid=$AID", even for POST. Yep, that's Relais
 documented protocol eg https://relais.atlassian.net/wiki/display/ILL/Find+Item