Skip to content

Development Guide

This guide describes the development workflow for the F5 XC API Enrichment Pipeline.

Terminal window
# Clone the repository
git clone https://github.com/f5xc-salesdemos/api-specs-enriched.git
cd api-specs-enriched
# Create virtual environment and install dependencies
make install
# Install pre-commit hooks
make pre-commit-install
# Download specs and run pipeline
make build
# Preview documentation locally
make serve
Terminal window
# Quick rebuild (uses cached specs)
make rebuild
# Run all quality checks
make pre-commit-run
# Preview documentation
make serve
┌─────────────────────┐ ┌─────────────────────────────┐
│ specs/original/ │────▶│ docs/specifications/api/ │
│ (READ-ONLY) │ │ (GENERATED) │
│ - Downloaded │ │ - Domain specs │
│ - Gitignored │ │ - Master spec │
│ - ETag cached │ │ - GitHub Pages │
└─────────────────────┘ └─────────────────────────────┘
Download (ETag) → Enrich → Normalize → Merge → Lint → Serve
│ │ │ │ │
▼ ▼ ▼ ▼ ▼
270 specs Branding Fix refs 23 domains Spectral
+ Grammar + Types + Master rules
DirectoryPurposeGit Status
specs/original/F5 source specsGitignored
specs/discovered/API discovery outputTracked (openapi.json, session.json)
docs/specifications/api/Generated domain specsGitignored
scripts/Python pipeline scriptsTracked
config/Pipeline configurationTracked
reports/Generated reportsGitignored

Prerequisites:

  • VPN connection to F5 XC environment
  • Valid API credentials
Terminal window
# Set credentials
export F5XC_API_URL="https://your-tenant.console.ves.volterra.io/api"
export F5XC_API_TOKEN="your-api-token"
# Run discovery
make discover
# View results
jq '.statistics' specs/discovered/session.json
# Commit for CI/CD
make push-discovery

Discovery captures:

  • Actual required/optional fields
  • Enum values from live responses
  • Default values
  • Pattern validations
  • Response examples

Releases are automated:

  1. Daily schedule (6 AM UTC) or push to main triggers workflow
  2. ETag check determines if F5 specs changed
  3. Pipeline processes and enriches specs
  4. Version calculated from git tags: git describe --tags --abbrev=0
  5. Direct commit + tag created (no version bump PR)
  6. GitHub Release created with changelog
  7. Documentation deployed to GitHub Pages

Version Bump Rules:

ConditionBump TypeExample
[major] in commitMajor1.0.0 → 2.0.0
BREAKING CHANGE in commitMajor1.0.0 → 2.0.0
New domain spec addedMinor1.0.0 → 1.1.0
Any other changePatch1.0.0 → 1.0.1
Terminal window
# Create feature branch
git checkout -b feature/my-change
# Make changes to config or scripts
# Test locally
make pipeline
make lint
# Commit (pre-commit hooks run automatically)
git add .
git commit -m "feat: add new enrichment rule"
# Push and create PR
git push -u origin feature/my-change
gh pr create

Discovery explores the live F5 XC API to find:

  • Undocumented constraints: Required fields not marked in OpenAPI
  • Actual enum values: Real values seen in production
  • Default behaviors: Server-applied values when fields are omitted
  • Response patterns: Actual data shapes
config/discovery.yaml
discovery:
exploration:
namespaces:
- "system"
- "shared"
methods:
- "GET"
- "OPTIONS"
max_endpoints_per_run: 500
schema_inference:
sample_size: 3
detect_patterns: true
detect_constraints: true

Discovery adds x-discovered-* extensions to specs:

{
"properties": {
"name": {
"type": "string",
"x-discovered-required": true,
"x-discovered-pattern": "^[a-z][a-z0-9-]*$",
"x-discovered-examples": ["my-app", "prod-lb"]
}
}
}
reports/constraint-analysis.md
make constraint-report
f5xc-api-specs-v1.0.14.zip
├── openapi.json # Master combined spec
├── openapi.yaml # YAML format
├── domains/ # Individual domain specs
│ ├── api_security.json
│ ├── load_balancer.json
│ └── ...
├── index.json # Metadata
├── CHANGELOG.md # Release notes
└── README.md # Usage instructions
Terminal window
gh workflow run sync-and-enrich.yml
gh run watch
config/enrichment.yaml
enrichment:
branding:
replacements:
"Volterra": "F5 Distributed Cloud"
"VES": "F5 XC"
acronyms:
API: "Application Programming Interface"
DNS: "Domain Name System"
grammar:
enabled: true
language_tool: true
config/normalization.yaml
normalization:
orphan_refs:
fix: true
remove_if_unresolvable: true
empty_operations:
remove: true
type_standardization:
enabled: true
config/spectral.yaml
extends:
- spectral:oas
rules:
operation-operationId: error
operation-tags: warn

The enrichment pipeline uses vendor extensions to embed validation and default value metadata.

ExtensionMeaningImplication
x-f5xc-server-defaultThe F5 XC API server applies this value when the field is omittedField is optional; omitting it produces the documented default behavior
x-f5xc-recommended-valueThe F5 XC web console pre-populates this value for new resourcesField has no server default but this value represents typical configuration
x-f5xc-recommended-oneof-variantThe F5 XC console preselects this OneOf variantIdentifies the typical choice when multiple mutually exclusive options exist
x-f5xc-conflicts-withLists other properties that cannot be used together with this fieldProperty is part of a OneOf group; only one of the conflicting properties can be specified
ExtensionSourcePurpose
x-ves-required: "true"F5 XC original specField requires non-zero/non-empty value
x-f5xc-required-forEnrichment pipelineContext-specific required status

x-f5xc-required-for contexts:

  • create: Required when creating the resource
  • update: Required when updating the resource
  • minimum_config: Required for minimum viable configuration
ExtensionPurpose
x-f5xc-server-default: trueMarks server-applied defaults
x-f5xc-recommended-valueF5 XC console pre-populated value
x-f5xc-recommended-oneof-variantRecommended OneOf variant
x-f5xc-conflicts-withMutual exclusivity with other OneOf properties

Type: boolean

When true, indicates the accompanying default value is enforced by the F5 XC API server. Fields with this extension can be safely omitted from API requests — the server applies the default automatically.

use_http2:
type: boolean
default: false
x-f5xc-server-default: true

Type: any (matches field type)

Specifies a value that the F5 XC web console uses as a pre-populated default. This value is not server-enforced but represents the typical starting configuration for new resources created via the console.

timeout:
type: integer
x-f5xc-recommended-value: 3

Type: object (map of group name to variant name)

For schemas with mutually exclusive field groups, identifies which variant is the default or most common choice. The key is the OneOf group name and the value is the recommended variant field name.

healthcheckCreateSpecType:
type: object
x-f5xc-recommended-oneof-variant:
health_check: "http_health_check"

Type: array of strings

Added: v3.2.0 (Issue #494)

Declares mutual exclusivity relationships between OneOf group members. Auto-derived from x-ves-oneof-field-* extensions. This enables downstream tools (Terraform, CLI, MCP) to validate conflicts at schema level rather than runtime.

host_header:
type: string
x-f5xc-conflicts-with: ["use_origin_server_name"]
use_origin_server_name:
type: object
x-f5xc-conflicts-with: ["host_header"]

Use cases:

  • Terraform providers can generate validation rules
  • CLI tools can warn about conflicting field combinations
  • AI assistants can generate correct OneOf configurations
  • IDE extensions can provide conflict-aware autocompletion

Source: Auto-derived from F5 native x-ves-oneof-field-* extensions during pipeline enrichment.

The enricher inspects x-ves-validation-rules to infer required status:

RuleImplication
ves.io.schema.rules.message.required: "true"Field is required
ves.io.schema.rules.uint32.gte: NIf N >= 1 and no server default, field is required
ves.io.schema.rules.repeated.min_items: NIf N >= 1, array requires at least N items
ves.io.schema.rules.string.min_bytes: NIf N >= 1, string requires at least N bytes

Some resources accept empty specs because the server applies defaults:

ResourceServer-Applied Defaults
app_firewallmonitoring: \{\}, default_detection_settings: \{\}
rate_limiterlimits: [], user_identification: []
api_definitionswagger_specs: [], default api_groups
healthcheckjitter: 0, jitter_percent: 0, nested http_health_check defaults

For these resources, x-f5xc-required-for.create may be false even when x-ves-required is true.

PatternTypeExample
\{\}Empty object (choice selection)monitoring: \{\}
[]Empty arrayexpected_status_codes: []
0Numericjitter: 0
""Stringexpected_response: ""
falseBooleanuse_http2: false
  1. Create resource in F5 XC with minimal spec via API
  2. Read back the resource to see server-applied values
  3. Document defaults in config/discovered_defaults.yaml
  4. Run pipeline: make pipeline
  5. Verify with: jq '.components.schemas | to_entries[] | select(.key | contains("resource_name"))'

The pipeline runs on every commit to ensure consistency. For work-in-progress commits:

Terminal window
git commit --no-verify -m "WIP: work in progress"
# Run before final commit: make pre-commit-run
Terminal window
# Check VPN
ping your-tenant.console.ves.volterra.io
# Check credentials
echo $F5XC_API_TOKEN | head -c 10
# Check API URL format
echo $F5XC_API_URL
# Format: https://tenant.console.ves.volterra.io/api
Terminal window
# Check lint report
cat reports/lint-report.json | jq '.errors'

Fix issues in enrichment/normalization config, not the output files.

Version is derived from git tags (e.g., v2.0.38), eliminating race conditions that caused merge conflicts on concurrent PRs.

# Version is calculated dynamically from git tags
from scripts.utils.version_calculator import get_version_from_tags
version = get_version_from_tags() # Returns "2.0.38"

Generated specs are gitignored:

Terminal window
make build # Downloads and generates everything

Add exclusion to .pre-commit-config.yaml:

- id: check-added-large-files
exclude: ^path/to/large/file\.json$
TargetDescription
make buildFull build (download + pipeline)
make rebuildQuick rebuild (skip download)
make downloadDownload specs (ETag cached)
make download-forceForce download
make pipelineRun enrichment pipeline
make lintSpectral linting
make serveLocal documentation server
make discoverAPI discovery (VPN required)
make push-discoveryCommit discovery data
make cleanRemove generated files
make pre-commit-runRun all quality checks
VariablePurpose
F5XC_API_URLF5 XC tenant API URL
F5XC_API_TOKENAPI authentication token
FilePurpose
.etagLast downloaded ETag
CHANGELOG.mdAuto-generated changelog
config/enrichment.yamlEnrichment rules
config/normalization.yamlNormalization rules
config/discovery.yamlDiscovery settings
config/spectral.yamlLinting rules
scripts/utils/version_calculator.pyTag-based version calculation

Note: Version is derived from git tags (e.g., v2.0.38), not from a .version file.