OPEN SWAG GO
API Reference

Versioning Package

pkg/versioning compares OpenAPI specs across versions, detects breaking changes, and generates changelogs and migration guides.

import "github.com/gopackx/open-swag-go/pkg/versioning"

Differ

Compares two OpenAPI specs and produces a structured diff.

type Differ struct{}
 
func NewDiffer() *Differ

Methods

func (d *Differ) Compare(oldSpec, newSpec map[string]interface{}) (*Diff, error)
func (d *Differ) CompareFiles(oldPath, newPath string) (*Diff, error)

Compare takes two decoded OpenAPI specs (e.g. from json.Unmarshal into a map[string]interface{}). CompareFiles reads and decodes two spec files first.

Usage

differ := versioning.NewDiffer()
 
diff, err := differ.CompareFiles("spec-v1.json", "spec-v2.json")
if err != nil {
    log.Fatal(err)
}
 
fmt.Printf("Total changes: %d\n", len(diff.Changes))
fmt.Printf("Breaking: %d\n", len(diff.Breaking))

Diff

The result of comparing two specs.

type Diff struct {
    OldVersion string           // Version of the old spec
    NewVersion string           // Version of the new spec
    Changes    []Change         // All detected changes
    Breaking   []BreakingChange // Subset of changes that are breaking
    Summary    Summary          // Aggregate counts
}
 
func (d *Diff) HasBreakingChanges() bool

Summary

type Summary struct {
    AddedEndpoints    int
    RemovedEndpoints  int
    ModifiedEndpoints int
    BreakingChanges   int
}

Change

A single difference between two spec versions.

type Change struct {
    Type        ChangeType // added, removed, modified
    Path        string     // API path, e.g. "/users/{id}"
    Method      string     // HTTP method (when applicable)
    Description string     // Human-readable description
    IsBreaking  bool       // Whether this change is breaking
}

ChangeType constants

type ChangeType string
 
const (
    ChangeAdded    ChangeType = "added"
    ChangeRemoved  ChangeType = "removed"
    ChangeModified ChangeType = "modified"
)

BreakingChange

A change that may break existing API consumers.

type BreakingChange struct {
    Path      string // API path
    Method    string // HTTP method
    Reason    string // Why the change is breaking
    Migration string // Suggested migration step
}

What the differ detects

Compare and CompareFiles walk the two specs and flag the following as breaking changes:

  • Endpoint removed — a path+method that existed in old but not new.
  • Request body removed — for an endpoint where it existed before.
  • Required request body added — body added with required: true.
  • New required field in a request body schema.
  • Field type changed — JSON type or format of an existing request-body property differs. v1.2.0 added this — earlier versions defined BreakingTypeChanged but never produced entries for it.
  • Parameter removed — query/path/header/cookie parameter dropped.
  • Parameter type changed — schema type/format of an existing parameter differs (also new in v1.2.0).
  • New required parameter added.
  • Response code removed from an existing operation.

Each detected entry includes a migration hint via the auto-generated BreakingChange.Migration field, suitable for surfacing in changelogs.

Breaking change rules

type BreakingChangeType string
 
const (
    BreakingEndpointRemoved    BreakingChangeType = "endpoint_removed"
    BreakingParameterRemoved   BreakingChangeType = "parameter_removed"
    BreakingRequiredAdded      BreakingChangeType = "required_field_added"
    BreakingResponseRemoved    BreakingChangeType = "response_removed"
    BreakingTypeChanged        BreakingChangeType = "type_changed"
    BreakingRequestBodyRemoved BreakingChangeType = "request_body_removed"
    BreakingSecurityAdded      BreakingChangeType = "security_added"
)
 
type BreakingChangeRule struct {
    Type        BreakingChangeType
    Description string
    Severity    string // "error" or "warning"
}
 
func DefaultBreakingRules() []BreakingChangeRule
func IsBreaking(changeType BreakingChangeType) bool

ChangelogGenerator

Produces a structured changelog from a Diff.

type ChangelogGenerator struct{}
 
func NewChangelogGenerator() *ChangelogGenerator
func (g *ChangelogGenerator) Generate(diff *Diff) *ChangelogEntry
 
type ChangelogEntry struct {
    Version  string
    Date     time.Time
    Added    []string
    Changed  []string
    Removed  []string
    Fixed    []string
    Breaking []string
}
 
func (e *ChangelogEntry) ToMarkdown() string
 
// Convenience: build a Markdown changelog in one call.
func GenerateChangelog(diff *Diff) string

Usage

entry := versioning.NewChangelogGenerator().Generate(diff)
fmt.Println(entry.ToMarkdown())
 
// or, in one step:
fmt.Println(versioning.GenerateChangelog(diff))

MigrationGenerator

Produces a step-by-step migration guide from breaking changes.

type MigrationGenerator struct{}
 
func NewMigrationGenerator() *MigrationGenerator
func (g *MigrationGenerator) Generate(diff *Diff) *MigrationGuide
 
type MigrationGuide struct {
    FromVersion string
    ToVersion   string
    Steps       []MigrationStep
}
 
func (g *MigrationGuide) ToMarkdown() string
 
type MigrationStep struct {
    Title       string
    Description string
    Before      string
    After       string
    Endpoint    string
    Method      string
}

Quick Example

package main
 
import (
    "fmt"
    "log"
    "os"
 
    "github.com/gopackx/open-swag-go/pkg/versioning"
)
 
func main() {
    differ := versioning.NewDiffer()
    diff, err := differ.CompareFiles("spec-v1.json", "spec-v2.json")
    if err != nil {
        log.Fatal(err)
    }
 
    fmt.Printf("Changes: %d, Breaking: %d\n", len(diff.Changes), len(diff.Breaking))
 
    fmt.Println(versioning.GenerateChangelog(diff))
 
    if diff.HasBreakingChanges() {
        guide := versioning.NewMigrationGenerator().Generate(diff)
        os.WriteFile("MIGRATION.md", []byte(guide.ToMarkdown()), 0644)
    }
}