From 58f1d3b0e1a8bc5db96026c976836d9f02497fea Mon Sep 17 00:00:00 2001 From: Davide Grilli Date: Mon, 9 Feb 2026 15:33:32 +0100 Subject: [PATCH] feat: add CLI test client for interactive API testing --- cli_client.py | 168 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 168 insertions(+) create mode 100755 cli_client.py diff --git a/cli_client.py b/cli_client.py new file mode 100755 index 0000000..1046f33 --- /dev/null +++ b/cli_client.py @@ -0,0 +1,168 @@ +#!/usr/bin/env python3 +""" +Card Game CLI Client - Interactive testing tool for the backend API. +""" + +import requests +import json +import uuid + +BASE_URL = "http://localhost:8000" + +class CardGameClient: + def __init__(self): + self.token = None + self.session = requests.Session() + + def _headers(self): + if self.token: + return {"Authorization": f"Bearer {self.token}"} + return {} + + def _print_response(self, resp, label="Response"): + print(f"\n{label} ({resp.status_code}):") + try: + print(json.dumps(resp.json(), indent=2)) + except: + print(resp.text) + + def register(self, email, password, nickname): + resp = self.session.post(f"{BASE_URL}/auth/register", json={ + "email": email, + "password": password, + "nickname": nickname + }) + self._print_response(resp, "Register") + if resp.status_code == 200: + data = resp.json() + self.token = data.get("access_token") + print("✓ Logged in automatically after registration.") + + def login(self, email, password): + resp = self.session.post(f"{BASE_URL}/auth/login", json={ + "email": email, + "password": password + }) + self._print_response(resp, "Login") + if resp.status_code == 200: + self.token = resp.json()["access_token"] + print("✓ Token saved.") + + def me(self): + resp = self.session.get(f"{BASE_URL}/me/profile", headers=self._headers()) + self._print_response(resp, "My Profile") + + resp = self.session.get(f"{BASE_URL}/me/wallet", headers=self._headers()) + self._print_response(resp, "My Wallet") + + def collection(self): + resp = self.session.get(f"{BASE_URL}/me/collection", headers=self._headers()) + self._print_response(resp, "My Collection") + + def chests(self): + resp = self.session.get(f"{BASE_URL}/catalog/chests") + self._print_response(resp, "Available Chests") + + def cards(self): + resp = self.session.get(f"{BASE_URL}/catalog/cards") + self._print_response(resp, "All Cards") + + def open_chest(self, chest_id, idempotency_key=None): + headers = self._headers() + if idempotency_key: + headers["Idempotency-Key"] = idempotency_key + else: + headers["Idempotency-Key"] = str(uuid.uuid4()) + + resp = self.session.post(f"{BASE_URL}/chests/{chest_id}/open", headers=headers) + self._print_response(resp, "Chest Open Result") + + def profile(self, nickname): + resp = self.session.get(f"{BASE_URL}/profiles/{nickname}") + self._print_response(resp, f"Profile: {nickname}") + + def profile_collection(self, nickname): + resp = self.session.get(f"{BASE_URL}/profiles/{nickname}/collection") + self._print_response(resp, f"Collection: {nickname}") + +def print_help(): + print(""" +=== Card Game CLI === +Commands: + register - Create new account + login - Login to existing account + me - Show my profile and wallet + collection - Show my cards + chests - List available chests + cards - List all cards in catalog + open - Open a chest + profile - View public profile + profile_collection - View public collection + help - Show this help + quit / exit - Exit +""") + +def main(): + client = CardGameClient() + print_help() + + while True: + try: + cmd = input("\n> ").strip() + if not cmd: + continue + + parts = cmd.split() + command = parts[0].lower() + args = parts[1:] + + if command in ["quit", "exit", "q"]: + print("Goodbye!") + break + elif command == "help": + print_help() + elif command == "register": + if len(args) < 3: + print("Usage: register ") + else: + client.register(args[0], args[1], args[2]) + elif command == "login": + if len(args) < 2: + print("Usage: login ") + else: + client.login(args[0], args[1]) + elif command == "me": + client.me() + elif command == "collection": + client.collection() + elif command == "chests": + client.chests() + elif command == "cards": + client.cards() + elif command == "open": + if len(args) < 1: + print("Usage: open ") + else: + key = args[1] if len(args) > 1 else None + client.open_chest(args[0], key) + elif command == "profile": + if len(args) < 1: + print("Usage: profile ") + else: + client.profile(args[0]) + elif command == "profile_collection": + if len(args) < 1: + print("Usage: profile_collection ") + else: + client.profile_collection(args[0]) + else: + print(f"Unknown command: {command}. Type 'help' for commands.") + + except KeyboardInterrupt: + print("\nGoodbye!") + break + except Exception as e: + print(f"Error: {e}") + +if __name__ == "__main__": + main()