Skip to content

apimerger — OpenAPI Definition Merger

apimerger is a utility tool that merges multiple OpenAPI/Swagger definitions into a single unified API specification for PiVirt.

Property Value
Language Go 1.22+
Protocol CLI tool
Input OpenAPI 3.0 YAML/JSON
Output Merged OpenAPI spec
Config /etc/apimerger/config.yaml

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
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")]
  • 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
  • Schema Validation: Validate merged spec against OpenAPI 3.0
  • Reference Checking: Verify all $ref references
  • Consistency Checks: Ensure no duplicate operations
  • Client SDKs: Generate Go, TypeScript, Python clients
  • Server Stubs: Generate server implementation stubs
  • Documentation: Generate API documentation
# apimerger configuration
merge:
# 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
# Validation
validation:
enabled: true
strict: true
check_references: true
# Code generation
generation:
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"
# Logging
logging:
level: "info"
format: "json"
output: "stdout"
Terminal window
# Merge all specs
apimerger merge --config /etc/apimerger/config.yaml
# Merge specific specs
apimerger merge \
--input /path/to/pivirtd.yaml \
--input /path/to/agent.yaml \
--output /path/to/merged.yaml
# With path prefixing
apimerger merge \
--input /path/to/pivirtd.yaml --prefix /pivirtd \
--input /path/to/agent.yaml --prefix /agent \
--output /path/to/merged.yaml
Terminal window
# Validate merged spec
apimerger validate --spec /path/to/merged.yaml
# Strict validation
apimerger validate --spec /path/to/merged.yaml --strict
Terminal window
# Generate all clients
apimerger generate --spec /path/to/merged.yaml --output /path/to/generated
# Generate specific language
apimerger generate --spec /path/to/merged.yaml --language go --output /path/to/go-client
apimerger generate --spec /path/to/merged.yaml --language typescript --output /path/to/ts-client
apimerger generate --spec /path/to/merged.yaml --language python --output /path/to/py-client
Terminal window
# Copy component specs
cp /path/to/pivirtd/api/openapi.yaml /etc/apimerger/specs/pivirtd.yaml
cp /path/to/agent/api/openapi.yaml /etc/apimerger/specs/agent.yaml
cp /path/to/iscsiman/api/openapi.yaml /etc/apimerger/specs/iscsiman.yaml
Terminal window
apimerger merge --config /etc/apimerger/config.yaml
Terminal window
apimerger validate --spec /etc/apimerger/output/pivirt-api.yaml
Terminal window
apimerger generate --spec /etc/apimerger/output/pivirt-api.yaml --output /etc/apimerger/generated
// Go client
import "go.pilab.hu/cloud/virtpb/pilab"
client := pivirt.NewClient("https://agent.pilab.hu:8443")
vms, err := client.ListVMs(ctx, &pivirt.ListVMsRequest{})
// TypeScript client
import { VMServiceClient } from '@pilab/pivirt';
const client = new VMServiceClient('https://agent.pilab.hu:8443');
const vms = await client.listVMs({});
# Python client
from pivirt import VMServiceClient
client = VMServiceClient('https://agent.pilab.hu:8443')
vms = client.list_vms()

When multiple specs define the same path, apimerger adds component prefixes:

# Before merge
# pivirtd.yaml: /vms
# agent.yaml: /vms
# After merge
# /pivirtd/vms
# /agent/vms

When multiple specs define schemas with the same name:

# Before merge
# pivirtd.yaml: VM
# agent.yaml: VM
# After merge
# PivirtdVM
# AgentVM

When multiple specs define operations with the same ID:

# Before merge
# pivirtd.yaml: createVM
# agent.yaml: createVM
# After merge
# pivirtd_createVM
# agent_createVM
Terminal window
# Check input specs
apimerger validate --spec /path/to/input.yaml
# Check logs
apimerger merge --config /etc/apimerger/config.yaml --log-level debug
Terminal window
# Check specific errors
apimerger validate --spec /path/to/merged.yaml --verbose
# Fix common issues
# - Missing $ref targets
# - Duplicate operation IDs
# - Invalid schema references
Terminal window
# Check output directory permissions
ls -la /etc/apimerger/generated
# Check language-specific requirements
# Go: gofmt, goimports
# TypeScript: npm, tsc
# Python: python3, pip