Skip to main content

backstage-api.sh

Generic wrapper script for querying the local Backstage API with automatic authentication.

Features

  • Auto-detects kubectl context and extracts cluster name
  • Extracts API token from cluster-specific config file
  • Supports optional jq filtering
  • Works from anywhere in the workspace

Usage

./scripts/backstage-api.sh '<endpoint>' [jq-filter]

⚠️ IMPORTANT: Always quote the endpoint when using query parameters (?filter=...)

# ✅ Correct (with quotes)
./scripts/backstage-api.sh '/api/catalog/entities?filter=kind=Template'

# ❌ Wrong (without quotes - shell will expand the ?)
./scripts/backstage-api.sh /api/catalog/entities?filter=kind=Template

Examples

Basic Usage

# Get all entities
./scripts/backstage-api.sh /api/catalog/entities

# Get all templates (note the quotes!)
./scripts/backstage-api.sh '/api/catalog/entities?filter=kind=Template'

# Get specific entity
./scripts/backstage-api.sh /api/catalog/entities/by-name/template/default/cs-api-realm-template

With jq Filters

# Get template names only
./scripts/backstage-api.sh '/api/catalog/entities?filter=kind=Template' '.[] | .metadata.name'

# Get templates with tags
./scripts/backstage-api.sh '/api/catalog/entities?filter=kind=Template' '.[] | {name: .metadata.name, tags: .metadata.tags}'

# Check source tags
./scripts/backstage-api.sh '/api/catalog/entities?filter=kind=Template' '.[] | {name: .metadata.name, source_tags: (.metadata.tags | map(select(startswith("source:"))))}'

# Group by source tags
./scripts/backstage-api.sh '/api/catalog/entities?filter=kind=Template' '.[] | {name: .metadata.name, source_tags: (.metadata.tags | map(select(startswith("source:"))))}' | jq -s 'group_by(.source_tags | sort | join(",")) | map({source_tags: .[0].source_tags, count: length, examples: (map(.name) | .[0:5])})'

Filter Specific Templates

# Get local file template
./scripts/backstage-api.sh '/api/catalog/entities?filter=kind=Template' '.[] | select(.metadata.name == "cs-api-realm-template")'

# Get GitHub templates
./scripts/backstage-api.sh '/api/catalog/entities?filter=kind=Template' '.[] | select(.metadata.tags | contains(["source:github-discovered"]))'

# Get Crossplane templates
./scripts/backstage-api.sh '/api/catalog/entities?filter=kind=Template' '.[] | select(.metadata.tags | contains(["crossplane"]))'

Other Endpoints

# Get components
./scripts/backstage-api.sh '/api/catalog/entities?filter=kind=Component'

# Get APIs
./scripts/backstage-api.sh '/api/catalog/entities?filter=kind=API'

# Search
./scripts/backstage-api.sh '/api/search/query?term=crossplane'

How it Works

  1. Detects current kubectl context (e.g., osp-openportal, osp-openportal-oidc)
  2. Extracts cluster name from context (e.g., openportal)
  3. Looks for app-config.openportal.local.yaml in app-portal/
  4. Extracts the static API token from the config
  5. Makes authenticated request to http://localhost:7007
  6. Optionally pipes through jq for filtering

Note: Multiple contexts pointing to the same cluster (e.g., with different auth methods) share the same config file.

Requirements

  • Backstage running on http://localhost:7007
  • Cluster-specific config file with static API token (generated by cluster-config.sh)
  • kubectl configured with current context
  • jq installed for JSON processing

Claude Code Integration

To allow Claude Code to use this script without manual confirmation, add it to your allowed commands in .claude/settings.local.json:

{
"allowedCommands": [
"Bash(./scripts/backstage-api.sh:*)"
]
}

Benefit: More secure than allowing curl globally - restricts Claude to only this specific script.

Troubleshooting

Config file not found:

# Check current context and cluster name
kubectl config current-context
kubectl config view --minify -o jsonpath='{.contexts[0].context.cluster}'

# Verify config file exists (should match cluster name)
ls app-portal/app-config.*.local.yaml

# Re-run cluster-config.sh to generate config
./scripts/cluster-config.sh

No token found:

# Check token in config
grep -A2 "type: static" app-portal/app-config.*.local.yaml

Connection refused:

# Verify Backstage is running
curl http://localhost:7007/api/catalog/entities | head