commit e297ef7ee0d3723ae93415b9e859241aee796226 Author: agatha Date: Sat Aug 26 12:15:48 2023 -0400 Initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..42f2907 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +.idea/ +.venv/ + +__pycache__/ +*.py[cod] diff --git a/README.md b/README.md new file mode 100644 index 0000000..1c2c8f6 --- /dev/null +++ b/README.md @@ -0,0 +1 @@ +# API Wrapper Boilerplate diff --git a/src/main.py b/src/main.py new file mode 100644 index 0000000..537c0df --- /dev/null +++ b/src/main.py @@ -0,0 +1,31 @@ +from wrapper import ApiWrapper + + +def main(): + """ + ApiWrapper example. + """ + # Initialize ApiWrapper + api = ApiWrapper('https://jsonplaceholder.typicode.com') + + # Test get_users method + users = api.get_users() + for user in users: + print(user) + + # Reinitialize ApiWrapper with broken proxy + # This should raise an InvalidRequestException + api = ApiWrapper( + 'https://jsonplaceholder.typicode.com', + proxies={'http': 'http://localhost:23451', 'https': 'http://localhost:23451'} + ) + + # Test broken proxy + users = api.get_users() + for user in users: + print(user) + + +if __name__ == '__main__': + main() + diff --git a/src/wrapper.py b/src/wrapper.py new file mode 100644 index 0000000..5245492 --- /dev/null +++ b/src/wrapper.py @@ -0,0 +1,113 @@ +""" +This module provides a wrapper for interacting with an API. + +The module contains the `ApiWrapper` class which offers convenient methods to access various +endpoints of the API using HTTP requests. It supports custom headers and proxies for +additional flexibility. +""" +import json +import requests +from requests.adapters import HTTPAdapter +from requests.packages.urllib3.util.retry import Retry + + +class InvalidApiResponse(Exception): + pass + + +class ApiRequestException(Exception): + pass + + +class ApiWrapper: + """ + Wrapper class for interacting with an API. + + This class provides convenient methods to access various endpoints of the + API using HTTP requests. It supports custom headers and proxies for + additional flexibility. + + Args: + base_url (str): The base URL of the API. + headers (dict, optional): Dictionary containing customer headers to be sent with each request. + proxies (dict, optional): Dictionary containing proxy settings to be used for requests. + + Attributes: + base_url (str): The base URL of the API. + session (requests.Session): Persistent HTTP session. + """ + + def __init__(self, base_url, headers=None, proxies=None): + self.base_url = base_url + self.session = requests.Session() + + retries = Retry(total=3, backoff_factor=1, status_forcelist=[429, 500, 502, 503, 504]) + self.session.mount('http://', HTTPAdapter(max_retries=retries)) + self.session.mount('https://', HTTPAdapter(max_retries=retries)) + + if headers: + self.session.headers.update(headers) + if proxies: + self.session.proxies.update(proxies) + + def __get(self, endpoint, params=None): + url = self.base_url + endpoint + + try: + response = self.session.get(url, params=params) + response.raise_for_status() + except requests.RequestException as e: + raise ApiRequestException(f'Failed to execute GET request: {str(e)}') + + try: + return response.json() + except json.JSONDecodeError: + raise InvalidApiResponse('Invalid JSON received') + + def __post(self, endpoint, data=None): + url = self.base_url + endpoint + + try: + response = self.session.post(url, data=data) + response.raise_for_status() + except requests.RequestException as e: + raise ApiRequestException(f'Failed to execute POST request: {str(e)}') + + try: + return response.json() + except json.JSONDecodeError: + raise InvalidApiResponse('Invalid JSON received') + + def __put(self, endpoint, data=None): + url = self.base_url + endpoint + + try: + response = self.session.put(url, data=data) + response.raise_for_status() + except requests.RequestException as e: + raise ApiRequestException(f'Failed to execute PUT request: {str(e)}') + + try: + return response.json() + except json.JSONDecodeError: + raise InvalidApiResponse('Invalid JSON received') + + def __delete(self, endpoint): + url = self.base_url + endpoint + + try: + response = self.session.delete(url) + response.raise_for_status() + except requests.RequestException as e: + raise ApiRequestException(f'Failed to execute DELETE request: {str(e)}') + + try: + return response.json() + except json.JSONDecodeError: + raise InvalidApiResponse('Invalid JSON received') + + def get_users(self): + endpoint = '/users' + response = self.__get(endpoint) + return response +