apimerger — OpenAPI Definition Merger
apimerger is a utility tool that merges multiple OpenAPI/Swagger definitions into a single unified API specification for PiVirt.
Technical Specifications
Section titled “Technical Specifications”| Property | Value |
|---|---|
| Language | Go 1.22+ |
| Protocol | CLI tool |
| Input | OpenAPI 3.0 YAML/JSON |
| Output | Merged OpenAPI spec |
| Config | /etc/apimerger/config.yaml |
Purpose
Section titled “Purpose”PiVirt consists of multiple components, each with its own API definition. apimerger combines these into a single, unified API specification that can be used for:
- Documentation: Generate comprehensive API docs
- Code Generation: Create client SDKs for multiple languages
- Testing: API testing and validation
- Integration: Third-party integrations
Architecture
Section titled “Architecture”flowchart TB
subgraph Apimerger["apimerger Architecture"]
subgraph CLI["CLI Interface"]
MRG_CMD["Merge Cmd"]
VAL_CMD["Validate"]
GEN_CMD["Generate Client"]
end
subgraph Core["Core Engine"]
PARSE["OpenAPI Parser"]
SPEC_MRG["Spec Merger"]
RESOLVE["Conflict Resolver<br/>(Naming, Paths)"]
end
CLI --> Core
end
IN_SPECS[("Input Specs<br/>(YAML/JSON)")] --> PARSE
SPEC_MRG --> OUT_SPEC[("Merged Spec<br/>(OpenAPI 3.0)")]
GEN_CMD --> CLIENTS[("Generated Clients")]
Key Features
Section titled “Key Features”API Merging
Section titled “API Merging”- Multi-Spec Merge: Combine multiple OpenAPI specs
- Conflict Resolution: Automatic naming conflict resolution
- Path Prefixing: Add component prefixes to paths
- Schema Deduplication: Merge identical schemas
Validation
Section titled “Validation”- Schema Validation: Validate merged spec against OpenAPI 3.0
- Reference Checking: Verify all $ref references
- Consistency Checks: Ensure no duplicate operations
Code Generation
Section titled “Code Generation”- Client SDKs: Generate Go, TypeScript, Python clients
- Server Stubs: Generate server implementation stubs
- Documentation: Generate API documentation
Configuration
Section titled “Configuration”Main Config (/etc/apimerger/config.yaml)
Section titled “Main Config (/etc/apimerger/config.yaml)”# apimerger configurationmerge: # Input specifications inputs: - name: "pivirtd" path: "/etc/apimerger/specs/pivirtd.yaml" prefix: "/pivirtd"
- name: "agent" path: "/etc/apimerger/specs/agent.yaml" prefix: "/agent"
- name: "iscsiman" path: "/etc/apimerger/specs/iscsiman.yaml" prefix: "/iscsiman"
- name: "deployer" path: "/etc/apimerger/specs/deployer.yaml" prefix: "/deployer"
- name: "osinfodb" path: "/etc/apimerger/specs/osinfodb.yaml" prefix: "/osinfodb"
# Output configuration output: path: "/etc/apimerger/output/pivirt-api.yaml" format: "yaml" # yaml | json
# Merge options options: # Add component prefix to paths prefix_paths: true
# Resolve naming conflicts resolve_conflicts: true
# Deduplicate schemas deduplicate_schemas: true
# Preserve operation IDs preserve_operation_ids: true
# Merge tags merge_tags: true
# Validationvalidation: enabled: true strict: true check_references: true
# Code generationgeneration: enabled: true output_dir: "/etc/apimerger/generated"
# Go client go: enabled: true package: "go.pilab.hu/cloud/virtpb/pilab" output: "/etc/apimerger/generated/go"
# TypeScript client typescript: enabled: true package: "@pilab/pivirt" output: "/etc/apimerger/generated/ts"
# Python client python: enabled: true package: "pivirt" output: "/etc/apimerger/generated/py"
# Logginglogging: level: "info" format: "json" output: "stdout"Merge Specifications
Section titled “Merge Specifications”# Merge all specsapimerger merge --config /etc/apimerger/config.yaml
# Merge specific specsapimerger merge \ --input /path/to/pivirtd.yaml \ --input /path/to/agent.yaml \ --output /path/to/merged.yaml
# With path prefixingapimerger merge \ --input /path/to/pivirtd.yaml --prefix /pivirtd \ --input /path/to/agent.yaml --prefix /agent \ --output /path/to/merged.yamlValidate Specification
Section titled “Validate Specification”# Validate merged specapimerger validate --spec /path/to/merged.yaml
# Strict validationapimerger validate --spec /path/to/merged.yaml --strictGenerate Clients
Section titled “Generate Clients”# Generate all clientsapimerger generate --spec /path/to/merged.yaml --output /path/to/generated
# Generate specific languageapimerger generate --spec /path/to/merged.yaml --language go --output /path/to/go-clientapimerger generate --spec /path/to/merged.yaml --language typescript --output /path/to/ts-clientapimerger generate --spec /path/to/merged.yaml --language python --output /path/to/py-clientExample Workflow
Section titled “Example Workflow”1. Prepare Input Specs
Section titled “1. Prepare Input Specs”# Copy component specscp /path/to/pivirtd/api/openapi.yaml /etc/apimerger/specs/pivirtd.yamlcp /path/to/agent/api/openapi.yaml /etc/apimerger/specs/agent.yamlcp /path/to/iscsiman/api/openapi.yaml /etc/apimerger/specs/iscsiman.yaml2. Merge Specifications
Section titled “2. Merge Specifications”apimerger merge --config /etc/apimerger/config.yaml3. Validate Merged Spec
Section titled “3. Validate Merged Spec”apimerger validate --spec /etc/apimerger/output/pivirt-api.yaml4. Generate Clients
Section titled “4. Generate Clients”apimerger generate --spec /etc/apimerger/output/pivirt-api.yaml --output /etc/apimerger/generated5. Use Generated Clients
Section titled “5. Use Generated Clients”// Go clientimport "go.pilab.hu/cloud/virtpb/pilab"
client := pivirt.NewClient("https://agent.pilab.hu:8443")vms, err := client.ListVMs(ctx, &pivirt.ListVMsRequest{})// TypeScript clientimport { VMServiceClient } from '@pilab/pivirt';
const client = new VMServiceClient('https://agent.pilab.hu:8443');const vms = await client.listVMs({});# Python clientfrom pivirt import VMServiceClient
client = VMServiceClient('https://agent.pilab.hu:8443')vms = client.list_vms()Conflict Resolution
Section titled “Conflict Resolution”Path Conflicts
Section titled “Path Conflicts”When multiple specs define the same path, apimerger adds component prefixes:
# Before merge# pivirtd.yaml: /vms# agent.yaml: /vms
# After merge# /pivirtd/vms# /agent/vmsSchema Conflicts
Section titled “Schema Conflicts”When multiple specs define schemas with the same name:
# Before merge# pivirtd.yaml: VM# agent.yaml: VM
# After merge# PivirtdVM# AgentVMOperation ID Conflicts
Section titled “Operation ID Conflicts”When multiple specs define operations with the same ID:
# Before merge# pivirtd.yaml: createVM# agent.yaml: createVM
# After merge# pivirtd_createVM# agent_createVMTroubleshooting
Section titled “Troubleshooting”Merge Failed
Section titled “Merge Failed”# Check input specsapimerger validate --spec /path/to/input.yaml
# Check logsapimerger merge --config /etc/apimerger/config.yaml --log-level debugValidation Failed
Section titled “Validation Failed”# Check specific errorsapimerger validate --spec /path/to/merged.yaml --verbose
# Fix common issues# - Missing $ref targets# - Duplicate operation IDs# - Invalid schema referencesGeneration Failed
Section titled “Generation Failed”# Check output directory permissionsls -la /etc/apimerger/generated
# Check language-specific requirements# Go: gofmt, goimports# TypeScript: npm, tsc# Python: python3, pip