def request(self, url, first_request_time=None, retry_counter=0, post_json=None): """Performs HTTP GET/POST with credentials, returning the body as JSON. :param url: URL extension for request. Should begin with a slash. :type url: string :param first_request_time: The time of the first request (None if no retries have occurred). :type first_request_time: datetime.datetime :param post_json: Parameters for POST endpoints :type post_json: dict :raises valhalla.utils.exceptions.ApiError: when the API returns an error. :returns: openrouteservice response body :rtype: dict """ if not first_request_time: first_request_time = datetime.now() elapsed = datetime.now() - first_request_time if elapsed > self.retry_timeout: raise exceptions.Timeout() if retry_counter > 0: # 0.5 * (1.5 ^ i) is an increased sleep time of 1.5x per iteration, # starting at 0.5s when retry_counter=1. The first retry will occur # at 1, so subtract that first. delay_seconds = 1.5**(retry_counter - 1) # Jitter this value by 50% and pause. time.sleep(delay_seconds * (random.random() + 0.5)) # Define the request params = {'access_token': self.key} authed_url = self._generate_auth_url( url, params, ) url_object = QUrl(self.base_url + authed_url) self.url = url_object.url() body = QJsonDocument.fromJson(json.dumps(post_json).encode()) request = QNetworkRequest(url_object) request.setHeader(QNetworkRequest.ContentTypeHeader, 'application/json') logger.log( "url: {}\nParameters: {}".format( self.url, # final_requests_kwargs json.dumps(post_json, indent=2)), 0) start = time.time() response: QgsNetworkReplyContent = self.nam.blockingPost( request, body.toJson()) self.response_time = time.time() - start try: self.handle_response(response, post_json['id']) except exceptions.OverQueryLimit: # Let the instances know smth happened self.overQueryLimit.emit() return self.request(url, first_request_time, retry_counter + 1, post_json) response_content = json.loads(bytes(response.content())) # Mapbox treats 400 errors with a 200 status code if 'error' in response_content: raise exceptions.ApiError(str(response_content['status_code']), response_content['error']) return response_content