REST API Server#

scafctl includes a built-in REST API server that exposes all major CLI features as HTTP endpoints. The server uses chi for routing and Huma for OpenAPI-compliant endpoint registration.

Starting the Server#

# Start with defaults (port 8080, host 127.0.0.1)
scafctl serve

# Start on a custom port
scafctl serve --port 9090

# Start with TLS
scafctl serve --enable-tls --tls-cert cert.pem --tls-key key.pem

# Custom API version prefix
scafctl serve --api-version v2

Configuration#

The server reads its configuration from the apiServer section of the scafctl config file:

apiServer:
  host: "127.0.0.1"   # use 0.0.0.0 to expose publicly
  port: 8080
  apiVersion: "v1"
  shutdownTimeout: "30s"
  requestTimeout: "60s"
  maxRequestSize: 10485760  # 10MB
  maxConcurrent: 1000

  tls:
    enabled: false
    cert: "/etc/ssl/cert.pem"
    key: "/etc/ssl/key.pem"

  cors:
    enabled: true
    allowedOrigins: ["*"]
    allowedMethods: ["GET", "POST", "PUT", "DELETE"]
    allowedHeaders: ["Content-Type", "Authorization"]
    maxAge: 3600

  rateLimit:
    global:
      maxRequests: 100
      window: "1m"

  auth:
    azureOIDC:
      enabled: false
      tenantId: "your-tenant-id"
      clientId: "your-client-id"

  compression:
    level: 6

  audit:
    enabled: true

  tracing:
    enabled: false

CLI flags override configuration file values.

Endpoints#

Health and Operational#

MethodPathDescription
GET/API root with HATEOAS links
GET/healthHealth check with component status
GET/health/liveLiveness probe (always 200)
GET/health/readyReadiness probe (503 during shutdown)
GET/metricsPrometheus metrics

Solutions#

MethodPathDescription
POST/v1/solutions/lintLint a solution file
POST/v1/solutions/inspectInspect a solution structure
POST/v1/solutions/dryrunDry-run a solution

Providers#

MethodPathDescription
GET/v1/providersList all providers
GET/v1/providers/{name}Get provider details
GET/v1/providers/{name}/schemaGet provider JSON schema

Evaluation#

MethodPathDescription
POST/v1/eval/celEvaluate a CEL expression
POST/v1/eval/templateEvaluate a Go template

Catalogs, Schemas, Config, Snapshots#

MethodPathDescription
GET/v1/catalogsList catalogs
GET/v1/catalogs/{name}Get catalog details
GET/v1/schemasList available schemas
GET/v1/schemas/{name}Get a specific schema
POST/v1/schemas/validateValidate data against a schema
GET/v1/configGet current configuration
GET/v1/settingsGet scafctl settings
GET/v1/snapshotsList snapshots
GET/v1/snapshots/{id}Get a specific snapshot

Explain and Diff#

MethodPathDescription
POST/v1/explainExplain a solution structure
POST/v1/diffDiff two solutions

Admin#

MethodPathDescription
GET/v1/admin/infoServer info (version, uptime)
POST/v1/admin/reload-configReload configuration
POST/v1/admin/clear-cacheClear caches

OpenAPI Specification#

Export the full OpenAPI spec without starting the server:

# JSON to stdout
scafctl serve openapi

# YAML to file
scafctl serve openapi --format yaml --output openapi.yaml

The spec is also served at /{version}/openapi.json when the server is running.

Authentication#

The server supports Azure Entra ID (formerly Azure AD) OIDC authentication. When enabled, all business endpoints require a valid JWT bearer token. Health probes and metrics bypass authentication.

apiServer:
  auth:
    azureOIDC:
      enabled: true
      tenantId: "00000000-0000-0000-0000-000000000000"
      clientId: "00000000-0000-0000-0000-000000000001"

Middleware Stack#

The server uses a two-layer middleware stack:

Global middleware (all routes including health probes):

  1. Recovery (panic handling)
  2. Request ID generation
  3. Trailing slash normalization
  4. Request logging

API middleware (business endpoints only):

  1. CORS
  2. Request timeout
  3. Concurrency throttling
  4. Authentication (Entra OIDC)
  5. Rate limiting
  6. Request size limits
  7. Response compression
  8. Security headers
  9. Prometheus metrics
  10. Audit logging
  11. OpenTelemetry tracing

Example: Lint a Solution via API#

curl -X POST http://localhost:8080/v1/solutions/lint \
  -H "Content-Type: application/json" \
  -d '{"path": "./solution.yaml"}'

Response:

{
  "file": "./solution.yaml",
  "findings": [],
  "errorCount": 0,
  "warnCount": 0,
  "infoCount": 0
}

Example: List Providers#

curl http://localhost:8080/v1/providers

Graceful Shutdown#

The server handles SIGINT and SIGTERM signals for graceful shutdown. During shutdown:

  1. The readiness probe returns 503
  2. In-flight requests are given time to complete (configurable via shutdownTimeout)
  3. New connections are rejected