docs: async def request(self, method, url, params=None, headers=None,
                        data=None, json=None, token_refresh_attempts=2,
                        **kwargs):
          """Make an asynchronous HTTP request.
  
          Args:
              method (str): HTTP method to use for the request.
              url (str): URL to be requested.
              params (dict): (optional) Query parameters for the request.
                  Defaults to ``None``.
              headers (dict): (optional) HTTP headers to send with the
                  request. Headers pass through to the request will
                  include :attr:`DEFAULT_REQUEST_HEADERS`.
              data (obj): (optional) A dictionary, bytes, or file-like
                  object to send in the body of the request.
              json (obj): (optional) Any json compatible python
                  object.
                  NOTE: json and body parameters cannot be used at the same time.
              token_refresh_attempts (int): (optional) Number of attempts a token
                  refresh should be performed.
          Returns:
              (str) HTTP response body.
          Raises:
              :exc:`.GCPHTTPError`: if any exception occurred,
                  specifically a :exc:`.GCPHTTPResponseError`, if the
                  exception is associated with a response status code.
  
          """
          if all([data, json]):
              msg = ('"data" and "json" request parameters can not be used '
                     'at the same time')
              logging.warn(msg)
              raise exceptions.GCPHTTPError(msg)
  
          req_headers = headers or {}
          req_headers.update(_utils.DEFAULT_REQUEST_HEADERS)
          req_kwargs = {
                  'params': params,
                  'headers': req_headers,
              }
  
          if data:
              req_kwargs['data'] = data
          if json:
              req_kwargs['json'] = json
  
          if token_refresh_attempts:
              if not await self.valid_token_set():
                  await self._auth_client.refresh_token()
                  token_refresh_attempts -= 1
  
          req_headers.update(
              {'Authorization': f'Bearer {self._auth_client.token}'}
          )
  
          request_id = kwargs.get('request_id', uuid.uuid4())
          logging.debug(_utils.REQ_LOG_FMT.format(
              request_id=request_id,
              method=method.upper(),
              url=url,
              kwargs=req_kwargs))
          try:
              async with self._session.request(method, url, **req_kwargs) as resp:
                  log_kw = {
                      'request_id': request_id,
                      'method': method.upper(),
                      'url': resp.url,
                      'status': resp.status,
                      'reason': resp.reason
                  }
                  logging.debug(_utils.RESP_LOG_FMT.format(**log_kw))
  
                  if resp.status in REFRESH_STATUS_CODES:
                      logging.warning(
                          f'[{request_id}] HTTP Status Code {resp.status}'
                          f' returned requesting {resp.url}: {resp.reason}')
                      if token_refresh_attempts:
                          logging.info(
                              f'[{request_id}] Attempting request to {resp.url} '
                              'again.')
                          return await self.request(
                              method, url,
                              token_refresh_attempts=token_refresh_attempts,
                              request_id=request_id,
                              **req_kwargs)
  
                      logging.warning(
                          f'[{request_id}] Max attempts refreshing auth token '
                          f'exhausted while requesting {resp.url}')
  
                  resp.raise_for_status()
  
                  return await resp.text()
          except aiohttp.ClientResponseError as e:
              # bad HTTP status; avoid leaky abstractions and wrap HTTP errors
              # with our own
              msg = f'[{request_id}] HTTP error response from {resp.url}: {e}'
              logging.error(msg, exc_info=e)
              raise exceptions.GCPHTTPResponseError(msg, resp.status)
          except exceptions.GCPHTTPResponseError as e:
              # from recursive call
              raise e
          except Exception as e:
              msg = f'[{request_id}] Request call failed: {e}'
              logging.error(msg, exc_info=e)
              raise exceptions.GCPHTTPError(msg)