Module pyaurorax.search.api.classes.request
Class definition for an AuroraX API request
Expand source code
# Copyright 2024 University of Calgary
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""
Class definition for an AuroraX API request
"""
import json
import requests
import datetime
from typing import Literal, Dict, List, Union
from ....exceptions import AuroraXAPIError, AuroraXUnauthorizedError, AuroraXMaintenanceError
from .response import AuroraXAPIResponse
class AuroraXAPIRequest:
"""
Class definition for an AuroraX API request
Attributes:
url (str): API endpoint URL for the request
method (str): the HTTP method to use. Valid values are: `get`, `post`, `put`, `delete`, `patch`
params (Dict): URL parameters to send in the request, defaults to `{}`
body (Dict): the body of the request (ie. post data), defaults to `{}`
headers (Dict): any headers to send as part of the request (in addition to the default ones), defaults to `{}`
null_response (bool): signifies if we expect a response from the API that has no body/data in it (ie.
requests to upload data that respond with just a 202 status code), defaults to `False`
"""
__API_KEY_HEADER_NAME = "x-aurorax-api-key"
def __init__(self,
aurorax_obj,
url: str,
method: Literal["get", "post", "put", "delete", "patch"],
params: Dict = {},
body: Union[List, Dict] = {},
headers: Dict = {},
null_response: bool = False):
self.__aurorax_obj = aurorax_obj
self.url = url
self.method = method
self.params = params
self.body = body
self.headers = headers
self.null_response = null_response
def __json_converter(self, o):
if (isinstance(o, datetime.datetime) is True):
return str(o)
def __merge_headers(self):
# set initial headers
all_headers = self.__aurorax_obj.api_headers
# add headers passed into the class
for key, value in self.headers.items():
all_headers[key.lower()] = value
# add api key
if self.__aurorax_obj.api_key:
all_headers[self.__API_KEY_HEADER_NAME] = self.__aurorax_obj.api_key
# return
return all_headers
def execute(self) -> AuroraXAPIResponse:
"""
Execute an AuroraX API request
Returns:
an `pyaurorax.search.api.AuroraXAPIResponse` object
Raises:
pyaurorax.exceptions.AuroraXAPIError: error during API call
"""
# sanitize data
body_santized = json.dumps(self.body, default=self.__json_converter)
# make request
try:
req = requests.request(self.method,
self.url,
headers=self.__merge_headers(),
params=self.params,
data=body_santized,
timeout=self.__aurorax_obj.api_timeout)
except requests.exceptions.Timeout:
raise AuroraXAPIError("API request timeout reached") from None
# check if authorization worked (raised by API or Nginx)
if (req.status_code == 401):
if (req.headers["Content-Type"] == "application/json"):
if ("error_message" in req.json()):
# this will be an error message that the API meant to send
raise AuroraXUnauthorizedError("API error code %d: %s" % (req.status_code, req.json()["error_message"]))
else:
raise AuroraXUnauthorizedError("API error code 401: unauthorized")
else:
raise AuroraXUnauthorizedError("API error code 401: unauthorized")
# check for 404 error (raised by API or by Nginx)
if (req.status_code == 404):
if (req.headers["Content-Type"] == "application/json"):
if ("error_message" in req.json()):
# this will be an error message that the API meant to send
raise AuroraXAPIError("API error code %d: %s" % (req.status_code, req.json()["error_message"]))
else:
# this will likely be a 404 from the API
raise AuroraXAPIError("API error code 404: not found")
else:
raise AuroraXAPIError("API error code 404: not found")
# check for server error
if (req.status_code == 500):
response_json = req.json()
if ("error_message" in response_json):
raise AuroraXAPIError("API error code %d: %s" % (req.status_code, response_json["error_message"]))
else:
raise AuroraXAPIError("API error code %d: %s" % (req.status_code, response_json))
# check for maintenance mode error
if (req.status_code == 502):
raise AuroraXAPIError("API error code %d: API inaccessible, bad gateway" % (req.status_code))
# check for maintenance mode error
if (req.status_code == 503):
response_json = req.json()
if ("maintenance mode" in response_json["error_message"].lower()):
raise AuroraXMaintenanceError(response_json["error_message"])
else:
raise AuroraXAPIError("API error code %d: %s" % (req.status_code, response_json["error_message"]))
# check content type
if (self.null_response is False):
if (req.headers["Content-Type"] == "application/json"):
if (len(req.content) == 0):
raise AuroraXAPIError("API error code %d: no response received" % (req.status_code))
else:
response_data = req.json()
else:
raise AuroraXAPIError("API error code %d: %s" % (req.status_code, req.content.decode()))
else:
if (req.status_code in [200, 201, 202, 204]):
response_data = None
else:
response_data = req.json()
# create response object
res = AuroraXAPIResponse(request=req, data=response_data, status_code=req.status_code)
# return
return res
def __str__(self) -> str:
return self.__repr__()
def __repr__(self) -> str:
return f"AuroraXAPIRequest(method='{self.method}', url='{self.url}')"
Classes
class AuroraXAPIRequest (aurorax_obj, url: str, method: Literal['get', 'post', 'put', 'delete', 'patch'], params: Dict = {}, body: Union[List, Dict] = {}, headers: Dict = {}, null_response: bool = False)
-
Class definition for an AuroraX API request
Attributes
url
:str
- API endpoint URL for the request
method
:str
- the HTTP method to use. Valid values are:
get
,post
,put
,delete
,patch
params
:Dict
- URL parameters to send in the request, defaults to
{}
body
:Dict
- the body of the request (ie. post data), defaults to
{}
headers
:Dict
- any headers to send as part of the request (in addition to the default ones), defaults to
{}
null_response
:bool
- signifies if we expect a response from the API that has no body/data in it (ie.
requests to upload data that respond with just a 202 status code), defaults to
False
Expand source code
class AuroraXAPIRequest: """ Class definition for an AuroraX API request Attributes: url (str): API endpoint URL for the request method (str): the HTTP method to use. Valid values are: `get`, `post`, `put`, `delete`, `patch` params (Dict): URL parameters to send in the request, defaults to `{}` body (Dict): the body of the request (ie. post data), defaults to `{}` headers (Dict): any headers to send as part of the request (in addition to the default ones), defaults to `{}` null_response (bool): signifies if we expect a response from the API that has no body/data in it (ie. requests to upload data that respond with just a 202 status code), defaults to `False` """ __API_KEY_HEADER_NAME = "x-aurorax-api-key" def __init__(self, aurorax_obj, url: str, method: Literal["get", "post", "put", "delete", "patch"], params: Dict = {}, body: Union[List, Dict] = {}, headers: Dict = {}, null_response: bool = False): self.__aurorax_obj = aurorax_obj self.url = url self.method = method self.params = params self.body = body self.headers = headers self.null_response = null_response def __json_converter(self, o): if (isinstance(o, datetime.datetime) is True): return str(o) def __merge_headers(self): # set initial headers all_headers = self.__aurorax_obj.api_headers # add headers passed into the class for key, value in self.headers.items(): all_headers[key.lower()] = value # add api key if self.__aurorax_obj.api_key: all_headers[self.__API_KEY_HEADER_NAME] = self.__aurorax_obj.api_key # return return all_headers def execute(self) -> AuroraXAPIResponse: """ Execute an AuroraX API request Returns: an `pyaurorax.search.api.AuroraXAPIResponse` object Raises: pyaurorax.exceptions.AuroraXAPIError: error during API call """ # sanitize data body_santized = json.dumps(self.body, default=self.__json_converter) # make request try: req = requests.request(self.method, self.url, headers=self.__merge_headers(), params=self.params, data=body_santized, timeout=self.__aurorax_obj.api_timeout) except requests.exceptions.Timeout: raise AuroraXAPIError("API request timeout reached") from None # check if authorization worked (raised by API or Nginx) if (req.status_code == 401): if (req.headers["Content-Type"] == "application/json"): if ("error_message" in req.json()): # this will be an error message that the API meant to send raise AuroraXUnauthorizedError("API error code %d: %s" % (req.status_code, req.json()["error_message"])) else: raise AuroraXUnauthorizedError("API error code 401: unauthorized") else: raise AuroraXUnauthorizedError("API error code 401: unauthorized") # check for 404 error (raised by API or by Nginx) if (req.status_code == 404): if (req.headers["Content-Type"] == "application/json"): if ("error_message" in req.json()): # this will be an error message that the API meant to send raise AuroraXAPIError("API error code %d: %s" % (req.status_code, req.json()["error_message"])) else: # this will likely be a 404 from the API raise AuroraXAPIError("API error code 404: not found") else: raise AuroraXAPIError("API error code 404: not found") # check for server error if (req.status_code == 500): response_json = req.json() if ("error_message" in response_json): raise AuroraXAPIError("API error code %d: %s" % (req.status_code, response_json["error_message"])) else: raise AuroraXAPIError("API error code %d: %s" % (req.status_code, response_json)) # check for maintenance mode error if (req.status_code == 502): raise AuroraXAPIError("API error code %d: API inaccessible, bad gateway" % (req.status_code)) # check for maintenance mode error if (req.status_code == 503): response_json = req.json() if ("maintenance mode" in response_json["error_message"].lower()): raise AuroraXMaintenanceError(response_json["error_message"]) else: raise AuroraXAPIError("API error code %d: %s" % (req.status_code, response_json["error_message"])) # check content type if (self.null_response is False): if (req.headers["Content-Type"] == "application/json"): if (len(req.content) == 0): raise AuroraXAPIError("API error code %d: no response received" % (req.status_code)) else: response_data = req.json() else: raise AuroraXAPIError("API error code %d: %s" % (req.status_code, req.content.decode())) else: if (req.status_code in [200, 201, 202, 204]): response_data = None else: response_data = req.json() # create response object res = AuroraXAPIResponse(request=req, data=response_data, status_code=req.status_code) # return return res def __str__(self) -> str: return self.__repr__() def __repr__(self) -> str: return f"AuroraXAPIRequest(method='{self.method}', url='{self.url}')"
Methods
def execute(self) ‑> AuroraXAPIResponse
-
Execute an AuroraX API request
Returns
an
AuroraXAPIResponse
objectRaises
AuroraXAPIError
- error during API call
Expand source code
def execute(self) -> AuroraXAPIResponse: """ Execute an AuroraX API request Returns: an `pyaurorax.search.api.AuroraXAPIResponse` object Raises: pyaurorax.exceptions.AuroraXAPIError: error during API call """ # sanitize data body_santized = json.dumps(self.body, default=self.__json_converter) # make request try: req = requests.request(self.method, self.url, headers=self.__merge_headers(), params=self.params, data=body_santized, timeout=self.__aurorax_obj.api_timeout) except requests.exceptions.Timeout: raise AuroraXAPIError("API request timeout reached") from None # check if authorization worked (raised by API or Nginx) if (req.status_code == 401): if (req.headers["Content-Type"] == "application/json"): if ("error_message" in req.json()): # this will be an error message that the API meant to send raise AuroraXUnauthorizedError("API error code %d: %s" % (req.status_code, req.json()["error_message"])) else: raise AuroraXUnauthorizedError("API error code 401: unauthorized") else: raise AuroraXUnauthorizedError("API error code 401: unauthorized") # check for 404 error (raised by API or by Nginx) if (req.status_code == 404): if (req.headers["Content-Type"] == "application/json"): if ("error_message" in req.json()): # this will be an error message that the API meant to send raise AuroraXAPIError("API error code %d: %s" % (req.status_code, req.json()["error_message"])) else: # this will likely be a 404 from the API raise AuroraXAPIError("API error code 404: not found") else: raise AuroraXAPIError("API error code 404: not found") # check for server error if (req.status_code == 500): response_json = req.json() if ("error_message" in response_json): raise AuroraXAPIError("API error code %d: %s" % (req.status_code, response_json["error_message"])) else: raise AuroraXAPIError("API error code %d: %s" % (req.status_code, response_json)) # check for maintenance mode error if (req.status_code == 502): raise AuroraXAPIError("API error code %d: API inaccessible, bad gateway" % (req.status_code)) # check for maintenance mode error if (req.status_code == 503): response_json = req.json() if ("maintenance mode" in response_json["error_message"].lower()): raise AuroraXMaintenanceError(response_json["error_message"]) else: raise AuroraXAPIError("API error code %d: %s" % (req.status_code, response_json["error_message"])) # check content type if (self.null_response is False): if (req.headers["Content-Type"] == "application/json"): if (len(req.content) == 0): raise AuroraXAPIError("API error code %d: no response received" % (req.status_code)) else: response_data = req.json() else: raise AuroraXAPIError("API error code %d: %s" % (req.status_code, req.content.decode())) else: if (req.status_code in [200, 201, 202, 204]): response_data = None else: response_data = req.json() # create response object res = AuroraXAPIResponse(request=req, data=response_data, status_code=req.status_code) # return return res