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..063ffb6 --- /dev/null +++ b/api/client.py @@ -0,0 +1,183 @@ +''' +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"): + ''' + 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. + + 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() + + 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. + + Raises: + requests.exceptions.HTTPError: For non-2xx status codes. + """ + url = f"{base_url}/register" + user_data = {"username": username, "password": password} + + response = requests.post(url, json=user_data) + response.raise_for_status() + + return response.json() + +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() + + 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. + + 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:", 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 unexpected error occurred: {e}") \ No newline at end of file