Ring-cli can transform OpenAPI 3.0+ specifications into ready-to-use command-line tools. This guide covers how to use OpenAPI specs with ring-cli, from fetching remote specs to mixing OpenAPI configs with regular YAML configs.
OpenAPI 3.0+ is a standard format for describing REST APIs. Ring-cli reads an OpenAPI spec and automatically generates CLI commands based on the API's paths, methods, parameters, and request bodies. This eliminates the need to manually write YAML configuration files for every API endpoint.
Key features:
- Automatic command hierarchy from API paths (e.g.,
/pets/{id}becomespets get --pet-id) - Curl/wget integration — commands execute via curl or wget with automatic header/body setup
- Parameter mapping — path, query, and body parameters become CLI flags
- Authentication support — Bearer tokens and API keys injected from environment variables
- Local and remote specs — use specs from your filesystem or fetch them from URLs
- Spec refreshing — update cached commands when the API spec changes
To use a local OpenAPI spec file:
- Obtain an OpenAPI spec (JSON or YAML). For example, save a spec to
./petstore.json:
curl -s https://api.example.com/openapi.json -o petstore.json- Initialize an alias with the spec:
ring-cli init --alias myapi --config-path openapi:./petstore.jsonRing-cli parses the spec, generates commands, and caches them. Your alias is ready to use.
- Use it:
# Tab completion works at every level
myapi <TAB> # shows: pets, orders, etc.
myapi pets <TAB> # shows: create, list, get, delete, etc.
myapi pets list --<TAB> # shows: --limit, --skip, etc.
# Run a command
myapi pets list --limit 10
myapi pets get --pet-id 42
myapi pets create --name "Fluffy" --tag "dog"To fetch and use a remote OpenAPI spec:
- Initialize with a URL:
ring-cli init --alias github --config-path openapi:https://api.example.com/openapi.yml- Ring-cli detects curl or wget, prompts for download consent (to protect against accidental network access):
Warning: ring-cli will use 'curl' to download https://api.example.com/openapi.yml
Continue? [Y/n]
- Type
yor use--yesto skip the prompt (useful for CI/CD):
ring-cli init --alias github --config-path openapi:https://api.example.com/openapi.yml --yes- The spec is downloaded, parsed, transformed, and cached. Commands work the same as with a local spec.
OpenAPI paths become a nested command hierarchy. The pattern is predictable:
| HTTP Method + Path | Command |
|---|---|
GET /pets |
myapi pets list |
POST /pets |
myapi pets create |
GET /pets/{petId} |
myapi pets get --pet-id <value> |
PUT /pets/{petId} |
myapi pets update --pet-id <value> |
DELETE /pets/{petId} |
myapi pets delete --pet-id <value> |
GET /pets/{petId}/toys |
myapi pets toys list --pet-id <value> |
POST /pets/{petId}/toys |
myapi pets toys create --pet-id <value> |
Rules:
- Path segments become subcommand levels (e.g.,
/pets/toys/items→pets toys items) - Path parameters (e.g.,
{petId}) become flags (e.g.,--pet-id) on the leaf command - HTTP methods map to verbs:
GET(collection) →list,GET(item) →get,POST→create,PUT→update,PATCH→patch,DELETE→delete - Collection vs item is determined by the last path segment: if it's a
{param}, it's an item operation; otherwise it's a collection operation
Given an API with:
GET /pets
POST /pets
GET /pets/{petId}
DELETE /pets/{petId}
GET /pets/{petId}/toys
Ring-cli generates:
myapi pets list
myapi pets create
myapi pets get --pet-id <value>
myapi pets delete --pet-id <value>
myapi pets toys list --pet-id <value>
When an operation accepts a JSON request body, ring-cli flattens the schema into flat flags with dot-notation. For example:
OpenAPI schema:
{
"type": "object",
"properties": {
"name": { "type": "string", "description": "Pet name" },
"owner": {
"type": "object",
"properties": {
"email": { "type": "string", "description": "Owner email" }
}
}
}
}Generated flags:
--name (Pet name)
--owner.email (Owner email)
Usage:
myapi pets create --name "Fluffy" --owner.email "alice@example.com"Ring-cli automatically constructs the JSON body:
{
"name": "Fluffy",
"owner": {
"email": "alice@example.com"
}
}Nesting is unlimited. A 3-level-deep schema like:
{
"owner": {
"address": {
"city": { "type": "string" }
}
}
}Generates the flag:
--owner.address.city
Usage:
myapi pets create --name "Spot" --owner.address.city "Portland"OpenAPI specs can define security schemes (Bearer tokens, API keys). Ring-cli extracts these and injects them as environment variables.
OpenAPI spec:
components:
securitySchemes:
bearerAuth:
type: http
scheme: bearer
security:
- bearerAuth: []Ring-cli converts the scheme name bearerAuth to the environment variable BEARER_AUTH_TOKEN and injects it:
Generated curl command:
curl -H 'Authorization: Bearer ${{env.BEARER_AUTH_TOKEN}}' https://api.example.com/petsBefore using the command, set the environment variable:
export BEARER_AUTH_TOKEN="your-api-token"
myapi pets listOpenAPI spec:
components:
securitySchemes:
apiKey:
type: apiKey
in: header
name: X-API-Key
security:
- apiKey: []Ring-cli converts to API_KEY_TOKEN and injects it:
curl -H 'X-API-Key: ${{env.API_KEY_TOKEN}}' https://api.example.com/petsThe environment variable name is derived from the security scheme name by converting camelCase to UPPER_SNAKE_CASE and appending _TOKEN:
| Scheme Name | Environment Variable |
|---|---|
bearerAuth |
BEARER_AUTH_TOKEN |
apiKey |
API_KEY_TOKEN |
github_token |
GITHUB_TOKEN_TOKEN |
MyCustomAuth |
MY_CUSTOM_AUTH_TOKEN |
When the API spec changes, refresh your cached commands:
myapi refresh-configurationRing-cli:
- Fetches the spec again (if remote)
- Compares hashes of the raw spec with the cached version
- If changed, shows the diff and prompts you to trust the new version:
Config 'pets' has changed. Trust new version? [y/N]
- Type
yto accept ornto keep the old version
Skip the prompt with --yes:
myapi refresh-configuration --yesIf the original spec URL or file is no longer available, refresh warns but keeps the cached copy working:
Warning: could not fetch https://api.example.com/openapi.yml
Using cached version from 2026-03-15
You can combine OpenAPI-generated commands with custom YAML commands in a single alias. Each config becomes a top-level subcommand:
ring-cli init --alias infra \
--config-path ./deploy.yml \
--config-path openapi:./api-spec.ymlUsage:
infra deploy staging # from deploy.yml
infra api pets list # from openapi:./api-spec.yml (config name: "api")
infra api pets get --pet-id 5Ring-cli generates the config name from the OpenAPI spec's info.title field (or falls back to the filename). To avoid conflicts, ensure config names are unique across all files.
A references file can include both regular and OpenAPI configs:
banner: "Welcome to Infrastructure CLI"
configs:
- deploy.yml
- monitoring.yml
- openapi:./petstore.json
- openapi:https://api.example.com/users.ymlRing-cli requires curl or wget to execute generated commands. At init time, ring-cli auto-detects which tool is available:
- Check for
curl --version - If not found, check for
wget --version - If neither is found, error: "curl or wget is required for OpenAPI support"
Generated commands use whichever tool was detected. The tool is remembered in the alias metadata, so it doesn't need to be re-detected on every command run.
If curl/wget becomes unavailable after init, ring-cli errors clearly:
Error: curl is not installed. Please install curl or wget to use this alias.
Install the missing tool and run refresh-configuration.
Ring-cli makes best-effort approximations for some OpenAPI features. Unsupported or partially-supported features:
| Feature | Behavior |
|---|---|
| Webhook callbacks | Skipped with warning |
| XML-only content types | Skipped; no JSON → no CLI command generated |
| multipart/form-data (file uploads) | Best-effort: generates --file flag for curl -F |
| $ref schemas | Not resolved; skipped with warning |
| OAuth2, OpenIDConnect | Skipped; only Bearer and API Key supported |
| Cookie authentication | Skipped |
| Query/cookie API keys | Skipped; only header API keys are supported |
| anyOf / oneOf schemas | Best-effort: generates flags for all possible fields |
| allOf schemas | Merged and flattened |
| Swagger 2.0 | Rejected with error: "Use OpenAPI 3.0+" |
| Server variables | Ignored; first server URL used as-is |
| Discriminators | Ignored; all variants treated as possible fields |
When unsupported features are encountered, ring-cli init prints a summary:
Generated 12 commands from OpenAPI spec
Skipped 2 operations (unsupported content types)
1 operation uses best-effort approximations
Use --verbose during init to see detailed warnings:
ring-cli init --alias api --config-path openapi:./spec.yml --verboseRing-cli could not find curl or wget on your system.
Solution: Install one of them:
# macOS
brew install curl
# Linux
sudo apt-get install curl
# Windows (PowerShell)
choco install curlThen run ring-cli init again.
Your OpenAPI spec is in Swagger 2.0 format.
Solution: Upgrade the spec to OpenAPI 3.0+ or use a tool like Swagger Editor to convert it.
Ring-cli could not parse the spec as valid JSON or YAML.
Troubleshooting:
- Validate the spec at Swagger Editor
- Check for JSON/YAML syntax errors
- Ensure the spec includes required fields:
openapi,info.title,paths
The spec URL is unreachable or returns an error.
Troubleshooting:
# Test the URL manually
curl -I https://api.example.com/openapi.yml
# Use --yes to skip confirmation and see full error
ring-cli init --alias api --config-path openapi:https://api.example.com/openapi.yml --yesSome API operations may be skipped due to unsupported content types.
Solution: Use --verbose to see details:
ring-cli init --alias api --config-path openapi:./spec.yml --verboseRing-cli will list all skipped operations and their reasons.
For complex nested schemas, dot-notation flags can be long:
myapi pets create --owner.address.country.name "USA"Solution: Use shell aliases or write a small wrapper script to provide shortcuts:
# In your shell config
alias my_create_pet='myapi pets create --owner.address.country.name'Create an alias from the public Petstore API:
ring-cli init --alias petstore --config-path openapi:https://petstore.swagger.io/v2/swagger.json --yes(Note: Swagger 2.0 will be rejected; see Known Limitations.)
For OpenAPI 3.0 example specs, visit apis.guru.
Example api.yml mixing OpenAPI with a manual deploy command:
ring-cli init --alias ops \
--config-path ./deploy.yml \
--config-path openapi:./user-api.jsonThen use it:
# Set auth token
export API_KEY_TOKEN="secret123"
# Use the API
ops api users list
ops api users get --user-id 42
# Use regular commands
ops deploy stagingTo keep specs fresh in CI/CD:
#!/bin/bash
# Fetch latest spec and refresh alias
curl -s https://api.example.com/openapi.json -o /tmp/latest.json
ring-cli init --alias api --config-path openapi:/tmp/latest.json --force --yesFor developers interested in how ring-cli transforms OpenAPI specs:
- Ring-cli parses the spec into an
openapiv3structure - Paths are organized into a command hierarchy tree based on non-parameter segments
- Path, query, and body parameters become flags
- Curl/wget commands are generated with proper headers, query strings, and JSON bodies
- The entire
Configurationstruct is cached in~/.ring-cli/aliases/<name>/ - On refresh, the raw spec hash is compared; if changed, you're prompted to trust the new version
- The cached copy continues working even if the original spec URL becomes unavailable