From 4fd83f3030690fdbf1b1269372b8aa498b8301ec Mon Sep 17 00:00:00 2001 From: Instech15 Date: Fri, 12 Sep 2025 10:12:34 +0100 Subject: [PATCH 1/2] Wrote a function using the library that registers a user via the endpoint from the OpenAPI spec and generated a function that fetches paginated poll data from , following the response schema. --- Polly-API | 0 api/client.py | 74 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 74 insertions(+) create mode 100644 Polly-API create mode 100644 api/client.py diff --git a/Polly-API b/Polly-API new file mode 100644 index 0000000..e69de29 diff --git a/api/client.py b/api/client.py new file mode 100644 index 0000000..7275882 --- /dev/null +++ b/api/client.py @@ -0,0 +1,74 @@ +''' +Client-side functions for interacting with the Polly-API. +''' +import requests +import json + +def get_polls(skip: int = 0, limit: int = 10, base_url: str = "http://localhost:8000"): + ''' + Fetches paginated poll data from the API. + + Args: + skip (int, optional): Number of items to skip. Defaults to 0. + limit (int, optional): Max number of items to return. Defaults to 10. + base_url (str, optional): The base URL of the API. + Defaults to "http://localhost:8000". + + Returns: + list: A list of polls. + ''' + url = f"{base_url}/polls" + params = {"skip": skip, "limit": limit} + + response = requests.get(url, params=params) + response.raise_for_status() # Raise an exception for bad status codes + + return response.json() + +def register_user(username, password, base_url="http://localhost:8000"): + """ + Registers a new user with the Polly-API. + + Args: + username (str): The username to register. + password (str): The password for the user. + base_url (str, optional): The base URL of the API. + Defaults to "http://localhost:8000". + + Returns: + dict: The JSON response from the API. + """ + url = f"{base_url}/register" + user_data = {"username": username, "password": password} + headers = {"Content-Type": "application/json"} + + response = requests.post(url, data=json.dumps(user_data), headers=headers) + + return response.json() + +# Example usage: +if __name__ == "__main__": + # Example for get_polls + try: + polls = get_polls(skip=0, limit=5) + print("Successfully fetched polls:") + for poll in polls: + print(poll) + except requests.exceptions.RequestException as e: + print(f"An error occurred while fetching polls: {e}") + + print("-" * 20) + + # Example for register_user + # Replace with a real username and password + new_username = "testuser" + new_password = "testpassword" + + try: + registration_response = register_user(new_username, new_password) + print("Registration successful:") + print(registration_response) + except requests.exceptions.ConnectionError as e: + print(f"Could not connect to the API: {e}") + except Exception as e: + print(f"An error occurred: {e}") \ No newline at end of file From 325a2c521bcf0534a5fb6027508d7569efbecc85 Mon Sep 17 00:00:00 2001 From: Instech15 Date: Fri, 12 Sep 2025 10:27:12 +0100 Subject: [PATCH 2/2] More updates --- api/client.py | 167 +++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 138 insertions(+), 29 deletions(-) diff --git a/api/client.py b/api/client.py index 7275882..063ffb6 100644 --- a/api/client.py +++ b/api/client.py @@ -1,8 +1,11 @@ ''' Client-side functions for interacting with the Polly-API. + +Each function raises `requests.exceptions.HTTPError` on non-2xx status codes. ''' import requests import json +import time def get_polls(skip: int = 0, limit: int = 10, base_url: str = "http://localhost:8000"): ''' @@ -11,18 +14,21 @@ def get_polls(skip: int = 0, limit: int = 10, base_url: str = "http://localhost: Args: skip (int, optional): Number of items to skip. Defaults to 0. limit (int, optional): Max number of items to return. Defaults to 10. - base_url (str, optional): The base URL of the API. + base_url (str, optional): The base URL of the API. Defaults to "http://localhost:8000". Returns: list: A list of polls. + + Raises: + requests.exceptions.HTTPError: For non-2xx status codes. ''' url = f"{base_url}/polls" params = {"skip": skip, "limit": limit} - + response = requests.get(url, params=params) - response.raise_for_status() # Raise an exception for bad status codes - + response.raise_for_status() + return response.json() def register_user(username, password, base_url="http://localhost:8000"): @@ -32,43 +38,146 @@ def register_user(username, password, base_url="http://localhost:8000"): Args: username (str): The username to register. password (str): The password for the user. - base_url (str, optional): The base URL of the API. + base_url (str, optional): The base URL of the API. Defaults to "http://localhost:8000". Returns: dict: The JSON response from the API. + + Raises: + requests.exceptions.HTTPError: For non-2xx status codes. """ url = f"{base_url}/register" user_data = {"username": username, "password": password} - headers = {"Content-Type": "application/json"} - - response = requests.post(url, data=json.dumps(user_data), headers=headers) - + + response = requests.post(url, json=user_data) + response.raise_for_status() + return response.json() -# Example usage: -if __name__ == "__main__": - # Example for get_polls - try: - polls = get_polls(skip=0, limit=5) - print("Successfully fetched polls:") - for poll in polls: - print(poll) - except requests.exceptions.RequestException as e: - print(f"An error occurred while fetching polls: {e}") +def login(username, password, base_url="http://localhost:8000"): + """ + Logs in a user and returns a JWT token. + + Args: + username (str): The username to login with. + password (str): The password for the user. + base_url (str, optional): The base URL of the API. + Defaults to "http://localhost:8000". + + Returns: + dict: A dictionary containing the access token and token type. + + Raises: + requests.exceptions.HTTPError: For non-2xx status codes. + """ + url = f"{base_url}/login" + data = {"username": username, "password": password} + headers = {"Content-Type": "application/x-www-form-urlencoded"} + + response = requests.post(url, data=data, headers=headers) + response.raise_for_status() - print("-" * 20) + return response.json() + +def cast_vote(poll_id: int, option_id: int, token: str, base_url: str = "http://localhost:8000"): + """ + Casts a vote on a poll. - # Example for register_user - # Replace with a real username and password - new_username = "testuser" + Args: + poll_id (int): The ID of the poll to vote on. + option_id (int): The ID of the option to vote for. + token (str): The JWT token for authentication. + base_url (str, optional): The base URL of the API. + Defaults to "http://localhost:8000". + + Returns: + dict: The JSON response from the API. + + Raises: + requests.exceptions.HTTPError: For non-2xx status codes. + """ + url = f"{base_url}/polls/{poll_id}/vote" + headers = {"Authorization": f"Bearer {token}"} + data = {"option_id": option_id} + + response = requests.post(url, headers=headers, json=data) + response.raise_for_status() + + return response.json() + +def get_poll_results(poll_id: int, base_url: str = "http://localhost:8000"): + """ + Retrieves the results for a specific poll. + + Args: + poll_id (int): The ID of the poll. + base_url (str, optional): The base URL of the API. + Defaults to "http://localhost:8000". + + Returns: + dict: The poll results. + + Raises: + requests.exceptions.HTTPError: For non-2xx status codes. + """ + url = f"{base_url}/polls/{poll_id}/results" + response = requests.get(url) + response.raise_for_status() + return response.json() + +# Example usage: +if __name__ == "__main__": + # Use a unique username to avoid conflicts + new_username = f"testuser_{int(time.time())}" new_password = "testpassword" - + try: + # 1. Register a new user + print(f"Registering user: {new_username}") registration_response = register_user(new_username, new_password) - print("Registration successful:") - print(registration_response) - except requests.exceptions.ConnectionError as e: - print(f"Could not connect to the API: {e}") + print("Registration successful:", registration_response) + + # 2. Log in to get a token + print("Logging in...") + login_response = login(new_username, new_password) + token = login_response.get("access_token") + if not token: + raise Exception("Failed to get access token from login response.") + print("Login successful.") + + # 3. Fetch polls + print("Fetching polls...") + polls = get_polls(limit=1) + if not polls: + print("No polls found. Cannot proceed with voting example.") + else: + example_poll = polls[0] + example_poll_id = example_poll.get("id") + if not example_poll_id: + raise Exception("Poll has no ID.") + + if example_poll.get("options"): + example_option = example_poll["options"][0] + example_option_id = example_option.get("id") + if not example_option_id: + raise Exception("Option has no ID.") + + # 4. Cast a vote + print(f"Casting vote on poll {example_poll_id}, option {example_option_id}...") + vote_response = cast_vote(example_poll_id, example_option_id, token) + print("Vote cast successfully:", vote_response) + + # 5. Get poll results + print(f"Fetching results for poll {example_poll_id}...") + results = get_poll_results(example_poll_id) + print("Poll results:", results) + else: + print(f"Poll {example_poll_id} has no options to vote on.") + + except requests.exceptions.RequestException as e: + print(f"An API error occurred: {e}") + if e.response: + print(f"Response body: {e.response.text}") except Exception as e: - print(f"An error occurred: {e}") \ No newline at end of file + print(f"An unexpected error occurred: {e}") \ No newline at end of file