Now that you have had some experience interacting with SOAP-based APIs, you can turn your attention to the other type of web service: REST. In order to send REST-based requests using Python, this lab will utilize the Python Requests library. To make this re-usable, a REST class will be implemented as a basic building block to send and receive the various request types (GET, POST, PUT, and DELETE) and to manage session re-use, so that each REST API, such as CUPI and CMS, can extend the class by adding the API-specific headers and parsing of the responses.
While you won't be able to test this code individually here, all subsequent REST modules will leverage it.
The REST class will use the following parameters:
Within this class, besides the __init__ method to initialize the class, there will be two methods:
Start implementing these methods using Visual Studio Code.
def __init__(self, host, username=None, password=None, base_url=None, headers={}, port=443, tls_verify=False):
"""
Initialize an object with the host, port, and base_url using the parameters passed in.
"""
self.host = host
self.port = str(port)
self.base_url = base_url
self.session = Session()
self.session.auth = HTTPBasicAuth(username, password)
self.session.verify = tls_verify
self.session.headers.update(headers)
# Set the URL using the parameters of the object and the api_method requested
# in a format such as: https//host:port/api/v1/api_method
url = "https://{}:{}{}/{}".format(self.host, self.port, self.base_url, api_method)
# Send the request and handle RequestException that may occur
try:
if http_method in ['GET', 'POST', 'PUT', 'DELETE']:
if http_method == 'GET':
raw_response = self.session.get(url, params=parameters)
elif http_method == 'POST':
raw_response = self.session.post(url, data=payload, params=parameters)
elif http_method == 'PUT':
raw_response = self.session.put(url, data=payload, params=parameters)
elif http_method == 'DELETE':
raw_response = self.session.delete(url)
result = {
'success': True,
'response': raw_response,
'message': 'Successful {} request to: {}'.format(http_method, url)
}
except RequestException as e:
result = {
'success': False,
'message': 'RequestException {} request to: {} :: {}'.format(http_method, url, e)}
return result
In most cases you will want to have some checks in place to see if a HTTP response code other than the 200-299 range was received. This can indicate congestion or other transient or permanent failure on the server side. You just need a method that you can call to check for that simple condition. In this lab, you won't implement any retries or other handling, but it could be added for specific cases.
def _check_response(self, raw_response):
"""
Evaluates a response status. If it has a non-2XX value, then set the 'success' result
to false and place the exception in the 'message'
:param raw_response: The raw response from a _send_request.
:returns: Returns a the same dictionary passed to it, with the 'success' and 'message'
keys modified, if needed.
:rtype: Dict
"""
pass
def _check_response(self, raw_response):
"""
Evaluates a response status. If it has a non-2XX value, then set the 'success' result
to false and place the exception in the 'message'
:param raw_response: The raw response from a _send_request.
:returns: Returns a the same dictionary passed to it, with the 'success' and 'message'
keys modified, if needed.
:rtype: Dict
"""
try:
# Raise HTTPError error for non-2XX responses
raw_response['response'].raise_for_status()
except HTTPError as e:
raw_response['success'] = False
raw_response['message'] = 'HTTPError Exception: {}'.format(e)
return raw_response
Now you have a method to send the requests and one to check the results for obvious return failures. Next you can implement each individual API to utilize these methods and parse the results according to their own requirements.