docs: def request(self, method, path, headers=None, params=None, data=None, **kwargs):
          """
          A wrapper around ``requests.request`` that handles boilerplate code specific to TruStar's API.
  
          :param str method: The method of the request (``GET``, ``PUT``, ``POST``, or ``DELETE``)
          :param str path: The path of the request, i.e. the piece of the URL after the base URL
          :param dict headers: A dictionary of headers that will be merged with the base headers for the SDK
          :param kwargs: Any extra keyword arguments.  These will be forwarded to the call to ``requests.request``.
          :return: The response object.
          """
  
          retry = self.retry
          attempted = False
          while not attempted or retry:
  
              # get headers and merge with headers from method parameter if it exists
              base_headers = self._get_headers(is_json=method in ["POST", "PUT"])
              if headers is not None:
                  base_headers.update(headers)
  
              url = "{}/{}".format(self.base, path)
  
              # make request
              response = requests.request(method=method,
                                          url=url,
                                          headers=base_headers,
                                          verify=self.verify,
                                          params=params,
                                          data=data,
                                          proxies=self.proxies,
                                          **kwargs)
              self.last_response = response
              attempted = True
  
              # log request
              self.logger.debug("%s %s. Trace-Id: %s. Params: %s", method, url, response.headers.get('Trace-Id'), params)
  
              # refresh token if expired
              if self._is_expired_token_response(response):
                  self._refresh_token()
  
              # if "too many requests" status code received, wait until next request will be allowed and retry
              elif retry and response.status_code == 429:
                  wait_time = ceil(response.json().get('waitTime') / 1000)
                  self.logger.debug("Waiting %d seconds until next request allowed." % wait_time)
  
                  # if wait time exceeds max wait time, allow the exception to be thrown
                  if wait_time <= self.max_wait_time:
                      time.sleep(wait_time)
                  else:
                      retry = False
  
              # request cycle is complete
              else:
                  retry = False
  
          # raise exception if status code indicates an error
          if 400 <= response.status_code < 600:
  
              # get response json body, if one exists
              resp_json = None
              try:
                  resp_json = response.json()
              except:
                  pass
  
              # get message from json body, if one exists
              if resp_json is not None and 'message' in resp_json:
                  reason = resp_json['message']
              else:
                  reason = "unknown cause"
  
              # construct error message
              message = "{} {} Error (Trace-Id: {}): {}".format(response.status_code,
                                                                "Client" if response.status_code < 500 else "Server",
                                                                self._get_trace_id(response),
                                                                reason)
              # raise HTTPError
              raise HTTPError(message, response=response)
  
          return response