# swagger-cli A fast, cache-first CLI for exploring OpenAPI specifications. Built for engineering teams and AI agents. **Key properties:** - Query latency: <50ms on cached specs (index-backed, no raw spec parsing) - First query: <2s including fetch + index build - Robot mode: 100% structured JSON output with versioned schema contract - Exit codes: Consistent, actionable, concurrency-safe (14 error types, codes 2-16) - Offline-capable: all queries work without network after initial fetch ## Install ```bash cargo install --path . ``` Requires Rust 2024 edition. ## Quick Start ```bash # Fetch and cache a spec swagger-cli fetch https://petstore3.swagger.io/api/v3/openapi.json --alias petstore # List endpoints swagger-cli list petstore # Search across the API swagger-cli search petstore "pet" # Show endpoint details swagger-cli show petstore "/pet/{petId}" --method GET # Browse schemas swagger-cli schemas petstore # Machine-readable output (for agents) swagger-cli list petstore --robot ``` ## Commands ### fetch Download and cache an OpenAPI spec. ```bash swagger-cli fetch --alias [OPTIONS] ``` `` accepts HTTP/HTTPS URLs, `file://` paths, relative paths, or `-` for stdin. | Option | Description | |--------|-------------| | `--alias ` | Required. Must match `^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$` | | `-H, --header
` | Additional HTTP header (repeatable, format: `"Name: Value"`) | | `--bearer ` | Bearer token for Authorization header | | `--auth-profile ` | Auth profile name from config.toml | | `--force` | Overwrite existing alias | | `--timeout-ms ` | HTTP request timeout in milliseconds (default: 10000) | | `--max-bytes ` | Maximum response size in bytes (default: 26214400 / ~25 MB) | | `--retries ` | Retries on transient errors (default: 2) | | `--allow-private-host ` | Bypass SSRF protection for this host (repeatable) | | `--allow-insecure-http` | Permit plain HTTP | | `--resolve-external-refs` | Fetch and inline external `$ref` entries | | `--ref-allow-host ` | Allowed host for external ref fetching (repeatable, required with `--resolve-external-refs`) | | `--ref-max-depth ` | Maximum chain depth for transitive external refs (default: 10) | | `--ref-max-bytes ` | Maximum total bytes fetched for external refs (default: 10485760 / ~10 MB) | ### list List endpoints from a cached spec. ```bash swagger-cli list [ALIAS] [OPTIONS] ``` | Option | Description | |--------|-------------| | `--all-aliases` | Query across every cached alias | | `-m, --method ` | Filter by HTTP method (case-insensitive) | | `-t, --tag ` | Filter by tag | | `-p, --path ` | Filter by path pattern (regex) | | `--sort ` | Sort order: path (default), method, or tag | | `-n, --limit ` | Maximum results (default: 50) | | `-a, --all` | Show all results (no limit) | ### show Display details of a specific endpoint. ```bash swagger-cli show [OPTIONS] ``` | Option | Description | |--------|-------------| | `-m, --method ` | HTTP method to show. Required when path has multiple methods | | `--expand-refs` | Expand `$ref` entries inline | | `--max-depth ` | Maximum depth for ref expansion (default: 3) | Output includes the full operation object: summary, description, tags, operationId, security, parameters (path/query/header/cookie), request body, and response schemas with status codes. Circular references are detected and annotated with `{"$circular_ref": "..."}`. ### search Full-text search across endpoints and schemas. ```bash swagger-cli search [ALIAS] [OPTIONS] ``` When using `--all-aliases`, the first positional argument is treated as the query. | Option | Description | |--------|-------------| | `--all-aliases` | Search across every cached alias | | `--case-sensitive` | Case-sensitive matching | | `--exact` | Match query as exact phrase | | `--in ` | Fields to search (comma-separated): all (default), paths, descriptions, schemas | | `--limit ` | Maximum results (default: 20) | Scoring is tokenized with field weights (path > summary > description) and term coverage boost, quantized to basis points for deterministic output. ### schemas Browse component schemas. ```bash swagger-cli schemas [OPTIONS] ``` | Option | Description | |--------|-------------| | `--name ` | Filter schema names by regex | | `--list` | List schemas (default mode) | | `--show ` | Show a specific schema by exact name | | `--expand-refs` | Expand `$ref` entries inline (show mode only) | | `--max-depth ` | Maximum depth for ref expansion (default: 3) | ### tags List tags from a cached spec with endpoint counts. ```bash swagger-cli tags ``` ### aliases Manage spec aliases. ```bash swagger-cli aliases [OPTIONS] ``` | Option | Description | |--------|-------------| | `--list` | List all aliases (default) | | `--show ` | Full details (URL, version, size, stats) | | `--rename ` | Rename an alias | | `--delete ` | Delete an alias and cached files | | `--set-default ` | Set the default alias (used when ALIAS is omitted in other commands) | ### sync Re-fetch and update cached specs. ```bash swagger-cli sync [ALIAS] [OPTIONS] ``` | Option | Description | |--------|-------------| | `--all` | Sync all cached specs | | `--dry-run` | Check for changes without writing | | `--force` | Re-fetch regardless of cache freshness | | `--details` | Include per-item change lists in output (capped at 200 items) | | `--auth ` | Auth profile name from config | | `--jobs ` | Maximum concurrent sync jobs, `--all` only (default: 4) | | `--per-host ` | Maximum concurrent requests per host, `--all` only (default: 2) | | `--max-failures ` | Abort after N alias failures, `--all` only | | `--resume` | Resume a previously interrupted `--all` sync | | `--allow-private-host ` | Bypass SSRF protection for this host (repeatable) | Uses ETag + Last-Modified for conditional fetches. Respects `Retry-After` headers with exponential backoff. Per-alias progress checkpoints enable resumable execution. ### diff Compare two spec versions (structural diff). ```bash swagger-cli diff [OPTIONS] ``` | Option | Description | |--------|-------------| | `--fail-on ` | Exit non-zero if changes at this level: `breaking` | | `--details` | Include per-item change descriptions | Output covers added/removed/modified endpoints and schemas with a summary and breaking-change flag. Useful as a CI gate for API contract changes. ### doctor Check cache health and diagnose issues. ```bash swagger-cli doctor [OPTIONS] ``` | Option | Description | |--------|-------------| | `--fix` | Attempt auto-repair | | `--alias ` | Check a specific alias only | Checks: directory permissions, meta.json generation + index_hash validation, index pointer validity, stale caches (30+ days), index version compatibility, and torn/partial cache state. Fix modes: (1) rebuild index from raw, (2) reconstruct meta from raw + index, (3) delete alias only as last resort. ### cache Manage the spec cache. ```bash swagger-cli cache [OPTIONS] ``` | Option | Description | |--------|-------------| | `--stats` | Show cache statistics (default) | | `--path` | Print the cache directory path | | `--prune-stale` | Remove aliases older than the stale threshold | | `--prune-threshold ` | Days before an alias is stale (default: 90) | | `--max-total-mb ` | LRU eviction until total size is under this limit | | `--dry-run` | Preview without deleting | ## Global Options Every command accepts these flags: | Flag | Description | |------|-------------| | `--robot` | Structured JSON output (auto-detects non-TTY) | | `--pretty` | Pretty-print JSON output | | `--network ` | `auto` (default), `online-only`, or `offline` | | `--config ` | Path to config file (or `SWAGGER_CLI_CONFIG` env var) | ## Robot Mode All commands support `--robot` for structured JSON output. Success: ```json { "ok": true, "data": { ... }, "meta": { "schema_version": 1, "tool_version": "0.1.0", "command": "list", "duration_ms": 12 } } ``` Errors emit JSON to stderr: ```json { "ok": false, "error": { "code": "ALIAS_NOT_FOUND", "message": "Alias not found: myapi", "suggestion": "Run 'swagger-cli aliases --list' to see available aliases." }, "meta": { ... } } ``` ## Exit Codes | Code | Error | Suggestion | |------|-------|------------| | 0 | Success | | | 2 | `USAGE_ERROR` | Run `swagger-cli --help` | | 4 | `NETWORK_ERROR` | Check connectivity or use `--network offline` | | 5 | `INVALID_SPEC` | Verify URL points to valid OpenAPI 3.x JSON/YAML | | 6 | `ALIAS_EXISTS` | Use `--force` to overwrite | | 7 | `AUTH_ERROR` | Check auth profile in config.toml | | 8 | `ALIAS_NOT_FOUND` | Run `aliases --list` to see available | | 9 | `CACHE_LOCKED` | Wait or check for stale locks | | 10 | `CACHE_ERROR` | Run `doctor --fix` | | 11 | `CONFIG_ERROR` | Check config file, run `doctor` | | 12 | `IO_ERROR` | File system error | | 13 | `JSON_ERROR` | Invalid JSON/YAML parsing | | 14 | `CACHE_INTEGRITY` | Run `doctor --fix` or re-fetch | | 15 | `OFFLINE_MODE` | Use `--network auto` or `online-only` | | 16 | `POLICY_BLOCKED` | Use `--allow-private-host` or `--allow-insecure-http` | ## Configuration Config file location: `~/.config/swagger-cli/config.toml` (or set `SWAGGER_CLI_CONFIG`). ```toml [auth_profiles.corp_internal] credential_source = "env:MY_API_TOKEN" auth_type = "bearer" [auth_profiles.api_key] credential_source = "env:API_KEY" auth_type = "api_key" header = "X-API-Key" ``` `credential_source` supports `env:VAR_NAME` and `file:/path/to/token`. ## Cache Layout Specs are stored per-alias under `~/.cache/swagger-cli/aliases/{alias}/`: | File | Purpose | |------|---------| | `raw.source` | Original upstream bytes (YAML or JSON, lossless provenance) | | `raw.json` | Canonical normalized JSON (all queries operate on this) | | `index.json` | Precomputed query index (endpoints, schemas, tags, search data) | | `meta.json` | Fetch metadata, written last as commit marker | The four-file protocol provides crash consistency: `meta.json` is written last with a generation counter and content hash, so a torn write is always detectable by `doctor`. ## Security - **SSRF protection**: Blocks loopback, private ranges, and multicast addresses by default. Override per-host with `--allow-private-host`. - **DNS rebinding mitigation**: Validates resolved IP after redirects (5 redirect limit). - **Auth redaction**: Tokens are never printed in output or logs. - **Streaming byte limit**: `--max-bytes` prevents OOM on oversized or malicious specs. - **Network policy**: `--network offline` guarantees zero outbound connections. - **External refs are opt-in**: `--resolve-external-refs` must be explicitly set with an allowlist of permitted hosts. ## License MIT