okta/framework/ApiClient.py (91 lines of code) (raw):

import requests import json import time from okta.framework.Serializer import Serializer from okta.framework.OktaError import OktaError import six class ApiClient(object): def __init__(self, *args, **kwargs): if 'pathname' not in kwargs: raise ValueError('A pathname must be provided to create an ApiClient') if 'base_url' in kwargs and kwargs['base_url']: self.base_url = kwargs['base_url'] + kwargs['pathname'] elif len(args) > 0 and args[0]: self.base_url = args[0] + kwargs['pathname'] else: raise ValueError('A base_url must be provided to create an ApiClient') if 'api_token' in kwargs and kwargs['api_token']: self.api_token = kwargs['api_token'] elif len(args) > 1 and args[1]: self.api_token = args[1] else: raise ValueError('An api_token must be provied to create an ApiClient') self.api_version = 1 self.max_attempts = 4 self.headers = { 'Accept': 'application/json', 'Content-Type': 'application/json', 'Authorization': 'SSWS ' + self.api_token } if 'headers' in kwargs: self.headers.update(kwargs['headers']) def get(self, url, params=None, attempts=0): params_str = self.__dict_to_query_params(params) resp = requests.get(url + params_str, headers=self.headers) attempts += 1 if self.__check_response(resp, attempts): return resp else: return self.get(url, params, attempts) def put(self, url, data=None, params=None, attempts=0): if data: data = json.dumps(data, cls=Serializer) params_str = self.__dict_to_query_params(params) resp = requests.put(url + params_str, data=data, headers=self.headers) attempts += 1 if self.__check_response(resp, attempts): return resp else: return self.put(url, data, params, attempts) def post(self, url, data=None, params=None, attempts=0): if data: data = json.dumps(data, cls=Serializer, separators=(',', ':')) params_str = self.__dict_to_query_params(params) resp = requests.post(url + params_str, data=data, headers=self.headers) attempts += 1 if self.__check_response(resp, attempts): return resp else: return self.post(url, data, params, attempts) def delete(self, url, params=None, attempts=0): params_str = self.__dict_to_query_params(params) resp = requests.delete(url + params_str, headers=self.headers) attempts += 1 if self.__check_response(resp, attempts): return resp else: return self.delete(url, params, attempts) def get_path(self, url_path, params=None): return self.get(self.base_url + url_path, params) def put_path(self, url_path, data=None, params=None): return self.put(self.base_url + url_path, data, params) def post_path(self, url_path, data=None, params=None): return self.post(self.base_url + url_path, data, params) def delete_path(self, url_path, params=None): return self.delete(self.base_url + url_path, params) def __check_response(self, resp, attempts=1): if resp is None: raise ValueError("A response wasn't received") if 200 <= resp.status_code < 300: return True # If we made it this far, we need to handle an exception if attempts >= self.max_attempts or resp.status_code != 429: raise OktaError(json.loads(resp.text)) # Assume we're going to retry with exponential backoff time.sleep(2 ** (attempts - 1)) return False @staticmethod def __dict_to_query_params(d): if d is None or len(d) == 0: return '' param_list = [param + '=' + (str(value).lower() if type(value) == bool else str(value)) for param, value in six.iteritems(d) if value is not None] return '?' + "&".join(param_list)