Skip to content

Canonical Repository Structure

The canonical repository follows a specific directory layout that supports multiple schema formats and versioning strategies.

Complete Directory Structure

apis/
├── buf.yaml                 # org-wide lint/breaking policy
├── buf.work.yaml            # workspace aggregating version dirs
├── CODEOWNERS               # per-path ownership
├── catalog/
│  └── catalog.yaml          # generated index of APIs/owners/tags
├── proto/                   # Protocol Buffers
│  └── payments/
│     └── ledger/
│        ├── go.mod          # v1 module: module github.com/<org>/apis/proto/payments/ledger
│        ├── v1/
│        │  └── ledger.proto # package <org>.payments.ledger.v1
│        └── v2/
│           ├── go.mod       # v2 module: module github.com/<org>/apis/proto/payments/ledger/v2
│           └── ledger.proto # package <org>.payments.ledger.v2
├── openapi/                 # OpenAPI specifications
│  └── users/
│     └── v1/
│        ├── go.mod
│        └── users.yaml
├── avro/                    # Avro schemas
│  └── events/
│     └── v1/
│        ├── go.mod
│        └── user-events.avsc
├── jsonschema/              # JSON Schema definitions
│  └── config/
│     └── v1/
│        ├── go.mod
│        └── app-config.json
└── parquet/                 # Parquet schemas
   └── analytics/
      └── v1/
         ├── go.mod
         └── events.parquet

Key Configuration Files

buf.yaml (Organization-wide Policy)

version: v2
lint:
  use: [STANDARD]
  except:
    - PACKAGE_DIRECTORY_MATCH  # Allow flexible directory structure
breaking:
  use: [FILE, WIRE]
  except:
    - FIELD_SAME_JSON_NAME     # Allow field name changes

buf.work.yaml (Workspace Configuration)

version: v1
directories:
  - proto/**/v1
  - proto/**/v2
  # Add v3, v4, etc. as needed

CODEOWNERS (Per-API Ownership)

# Global fallback
* @org/api-governance

# Domain-specific ownership
/proto/payments/ @org/payments-team
/proto/users/ @org/identity-team
/openapi/gateway/ @org/platform-team

# Schema format ownership
/avro/ @org/data-engineering
/parquet/ @org/analytics-team

Versioning & Go Modules

Path Mapping

Every API has a deterministic set of coordinates derived from its canonical repo identity:

Coordinate Example
API ID proto/payments/ledger/v1
Source path proto/payments/ledger/v1
Proto package myorg.payments.ledger.v1
Go module (v1) github.com/myorg/apis/proto/payments/ledger
Go import (v1) github.com/myorg/apis/proto/payments/ledger/v1
Go module (v2+) github.com/myorg/apis/proto/payments/ledger/v2
Go import (v2+) github.com/myorg/apis/proto/payments/ledger/v2
Git tag proto/payments/ledger/v1/v1.2.3

All paths derive from the single canonical repo github.com/<org>/apis. There is no separate Go distribution repo.

Semantic Import Versioning

APX follows Go's semantic import versioning:

  • v1 modules: No /v1 suffix in module path
  • module github.com/<org>/apis/proto/payments/ledger
  • v2+ modules: Include /vN suffix
  • module github.com/<org>/apis/proto/payments/ledger/v2

Directory vs Package vs Module

  • Directory Structure


    proto/payments/ledger/
    ├── v1/ (files)
    └── v2/ (files)
    
  • Proto Package Names


    <org>.payments.ledger.v1
    <org>.payments.ledger.v2
    
  • Go Module Paths


    github.com/<org>/apis/proto/payments/ledger (v1)
    github.com/<org>/apis/proto/payments/ledger/v2
    

Example go.mod Files

v1 module (no version suffix):

module github.com/myorg/apis/proto/payments/ledger

go 1.21

v2 module (with version suffix):

module github.com/myorg/apis/proto/payments/ledger/v2

go 1.21

Tagging Strategy

Subdirectory Tags

APX uses subdirectory tags for each API version:

# v1 releases
proto/payments/ledger/v1/v1.0.0
proto/payments/ledger/v1/v1.2.3

# v2 releases  
proto/payments/ledger/v2/v2.0.0
proto/payments/ledger/v2/v2.1.0

# Other formats
openapi/users/v1/v1.0.0
avro/events/v1/v1.5.0

Tag Protection

Protect tag patterns to ensure only CI creates tags:

  • proto/**/v* - Protocol Buffer APIs
  • openapi/**/v* - OpenAPI specifications
  • avro/**/v* - Avro schemas
  • jsonschema/**/v* - JSON schemas
  • parquet/**/v* - Parquet schemas

Catalog Generation

The catalog/catalog.yaml file is automatically generated by CI and provides searchable metadata:

version: 1
generated_at: "2024-01-15T10:30:00Z"

apis:
  - path: proto/payments/ledger
    kind: proto
    latest_version: v1.2.3
    description: "Ledger service for payment processing"
    owners: ["@org/payments-team"]
    tags:
      - v1.0.0
      - v1.1.0
      - v1.2.3

  - path: openapi/users  
    kind: openapi
    latest_version: v1.0.0
    description: "User management REST API"
    owners: ["@org/identity-team"]
    tags:
      - v1.0.0

This catalog enables: - apx search functionality - API discovery and browsing - Automated documentation generation - Dependency analysis

Multi-Format Considerations

Format-Specific Directories

Each schema format has its own top-level directory:

  • proto/: Protocol Buffers with buf integration
  • openapi/: OpenAPI 3.0+ specifications
  • avro/: Avro schema definitions
  • jsonschema/: JSON Schema validation rules
  • parquet/: Parquet schema definitions

Shared Tooling

While directories are separate, APX provides unified tooling:

# Works across all formats
apx lint          # Format-specific linting
apx breaking      # Format-specific breaking change detection  
apx search        # Search across all APIs
apx gen <lang>    # Code generation for supported formats

Best Practices

Directory Naming

  • Use kebab-case for directory names: user-service, payment-gateway
  • Group related APIs under common domains: payments/, users/, analytics/
  • Keep names concise but descriptive

Ownership Boundaries

  • Assign clear ownership via CODEOWNERS
  • One team per API path for accountability
  • API governance team as fallback owners

Versioning Strategy

  • Start with v1, add v2 only when introducing breaking changes
  • Keep v1 maintained until consumers migrate
  • Use semantic versioning for all releases

Documentation

  • Include README.md in each API directory
  • Document breaking changes in CHANGELOG.md
  • Use proto comments for API documentation