From d9c7442e76ee3343b05d905d97db52afa7d8e64c Mon Sep 17 00:00:00 2001 From: 7000pctAUTO Date: Wed, 4 Feb 2026 13:34:38 +0000 Subject: [PATCH] Add core modules: CLI, recorder, server, snapshot manager --- api_snapshot/cli/record.py | 114 +++++++++++++++++++++++++++++++++++++ 1 file changed, 114 insertions(+) create mode 100644 api_snapshot/cli/record.py diff --git a/api_snapshot/cli/record.py b/api_snapshot/cli/record.py new file mode 100644 index 0000000..b5fb728 --- /dev/null +++ b/api_snapshot/cli/record.py @@ -0,0 +1,114 @@ +from datetime import datetime +from typing import Any + +import click +from rich.console import Console +from rich.table import Table + +from api_snapshot.recorder import record_session +from api_snapshot.snapshot import save_snapshot + +console = Console() + + +@click.command() +@click.argument("url") +@click.option("--name", "-n", required=True, help="Name for the snapshot") +@click.option("--method", "-m", default="GET", help="HTTP method") +@click.option("--headers", "-H", multiple=True, help="Request headers") +@click.option("--body", "-d", default=None, help="Request body") +@click.option("--description", "-D", default=None, help="Snapshot description") +@click.option("--tag", multiple=True, help="Tags for the snapshot") +def record( + url: str, + name: str, + method: str, + headers: tuple[str, ...], + body: str | None, + description: str | None, + tag: tuple[str, ...], +) -> None: + """Record a single HTTP request and save as a snapshot.""" + click.echo(f"Recording {method} {url}...") + + request_headers = {} + for header in headers: + if ":" in header: + key, value = header.split(":", 1) + request_headers[key.strip()] = value.strip() + + request_body = body + if body and body.startswith("@"): + file_path = body[1:] + with open(file_path, "r") as f: + request_body = f.read() + + session_data = record_session( + url=url, + method=method, + headers=request_headers, + body=request_body, + ) + + snapshot = save_snapshot( + name=name, + session_data=session_data, + description=description, + tags=list(tag), + source_url=url, + ) + + click.echo(f"Snapshot saved: {snapshot}") + + +@click.command() +@click.argument("config_file", type=click.File("r")) +@click.option("--name", "-n", required=True, help="Name for the snapshot") +@click.option("--description", "-D", default=None, help="Snapshot description") +@click.option("--delay", default=1.0, help="Delay between requests in seconds") +def record_multi( + config_file: click.File, + name: str, + description: str | None, + delay: float, +) -> None: + """Record multiple requests from a JSON config file.""" + import json + + requests_config = json.load(config_file) + click.echo(f"Recording {len(requests_config)} requests...") + + table = Table(title="Recording Results") + table.add_column("Request") + table.add_column("Status") + table.add_column("Latency") + + for req in requests_config: + url = req.get("url", "") + method = req.get("method", "GET") + headers = req.get("headers", {}) + body = req.get("body") + + session_data = record_session( + url=url, + method=method, + headers=headers, + body=body, + ) + + status = session_data["response"]["status_code"] + latency = session_data["response"].get("latency_ms", 0) + url_display = url[:50] + "..." if len(url) > 50 else url + table.add_row(f"{method} {url_display}", str(status), f"{latency}ms") + + console.print(table) + + snapshot = save_snapshot( + name=name, + session_data=session_data, + description=description, + tags=[], + source_url=url, + ) + + click.echo(f"Snapshot saved: {snapshot}")