White Paper
Current as of: v1.52.0
Repository: github.com/erraggy/oastools
Documentation: pkg.go.dev/github.com/erraggy/oastools
License: MIT
oastools is a comprehensive, high-performance toolkit for working with OpenAPI Specification (OAS) documents in Go. It provides a complete solution for parsing, validating, fixing, converting, joining, diffing, walking, and generating code from API specifications spanning OAS 2.0 (Swagger) through OAS 3.2.0. The toolkit also ships an MCP server exposing all capabilities to AI-assisted development environments. oastools distinguishes itself through minimal dependencies, battle-tested quality against production APIs, significant performance optimizations, comprehensive security hardening, and native support for the OpenAPI Overlay Specification v1.0.0.
This white paper provides an in-depth exploration of oastools, covering its architecture, package ecosystem, integration with external specifications, real-world validation, and practical usage patterns. It serves as both a technical reference and an evaluation guide for teams considering adoption.
- Introduction and Motivation
- External Specification Compliance
- Package Architecture
- Parser Package
- Validator Package
- Fixer Package
- Converter Package
- Joiner Package
- Overlay Package
- Differ Package
- Generator Package
- Builder Package
- HTTP Validator Package
- Walker Package
- MCP Server
- Error Handling with oaserrors
- Performance Analysis
- Real-World Validation
- CLI Reference
- API Design Patterns
- Security Considerations
- Conclusion
- References
The OpenAPI Specification has become the de facto standard for describing HTTP APIs. As organizations adopt API-first development practices, the need for robust tooling to parse, validate, transform, and generate code from OpenAPI documents has grown significantly. The Go ecosystem, while rich in many areas, has historically lacked comprehensive OpenAPI tooling that addresses enterprise-scale requirements.
oastools was created to fill this gap, addressing several key pain points. First, existing Go libraries often lack support for newer OAS versions, particularly OAS 3.1.x with its JSON Schema 2020-12 alignment, and the recently released OAS 3.2.0 with streaming and QUERY method support. Second, many OpenAPI tools bring extensive dependency trees, complicating builds, increasing binary sizes, and introducing potential security vulnerabilities. Third, repeatedly parsing the same document across validation, conversion, and generation pipelines creates unnecessary overhead at scale. Finally, generating idiomatic Go code that properly handles OAuth2 flows, Proof Key for Code Exchange (PKCE), and OpenID Connect (OIDC) discovery remains challenging with existing tools.
oastools addresses these challenges through a modular twelve-package architecture, each package designed to excel at a specific task while integrating seamlessly with others. In addition, a built-in MCP server exposes all capabilities over the Model Context Protocol, enabling AI-assisted API development workflows. The toolkit emphasizes correctness, performance, and developer experience.
The development of oastools follows several guiding principles. The toolkit maintains minimal dependencies, relying only on go.yaml.in/yaml/v4 for YAML parsing, golang.org/x/text for Unicode handling, golang.org/x/tools for import analysis during code generation, github.com/modelcontextprotocol/go-sdk for MCP server support, and github.com/stretchr/testify for testing. The parse-once pattern ensures documents flow through multiple operations without redundant parsing. All parser types include generated DeepCopy() methods for safe document mutation without serialization overhead. The toolkit supports OAS 2.0 through OAS 3.2.0 comprehensively, adapting behavior for version-specific features. Both functional options for one-off operations and reusable struct instances for batch processing are supported.
For hands-on examples demonstrating oastools capabilities, see the examples directory in the repository. The Petstore example showcases a complete workflow including parsing, validation, code generation, and server implementation.
oastools implements and integrates with several external specifications. Understanding these relationships is essential for evaluating the toolkit's capabilities and limitations.
The OpenAPI Specification (OAS) defines a standard, programming language-agnostic interface description for HTTP APIs. oastools supports the complete OAS version range as specified by the OpenAPI Initiative.
Supported Versions:
| Version | Specification URL | Key Features |
|---|---|---|
| OAS 2.0 | spec.openapis.org/oas/v2.0.html | Swagger foundation, definitions, host/basePath |
| OAS 3.0.0 | spec.openapis.org/oas/v3.0.0.html | requestBody, servers[], components |
| OAS 3.0.1 | spec.openapis.org/oas/v3.0.1.html | Clarifications to 3.0.0 |
| OAS 3.0.2 | spec.openapis.org/oas/v3.0.2.html | Additional clarifications |
| OAS 3.0.3 | spec.openapis.org/oas/v3.0.3.html | Bug fixes, clarifications |
| OAS 3.0.4 | spec.openapis.org/oas/v3.0.4.html | Latest 3.0.x patch release |
| OAS 3.1.0 | spec.openapis.org/oas/v3.1.0.html | JSON Schema 2020-12 alignment, webhooks |
| OAS 3.1.1 | spec.openapis.org/oas/v3.1.1.html | Clarifications to 3.1.0 |
| OAS 3.1.2 | spec.openapis.org/oas/v3.1.2.html | Latest 3.1.x patch release |
| OAS 3.2.0 | spec.openapis.org/oas/v3.2.0.html | QUERY method, streaming media types, tag hierarchies |
OAS 3.1.x JSON Schema Alignment:
OAS 3.1.x introduced significant changes by aligning with JSON Schema Draft 2020-12. Key differences that oastools handles include polymorphic type fields (string or array), nullable representation (type arrays including "null" rather than nullable: true), exclusiveMinimum/exclusiveMaximum as numbers rather than booleans, and new keywords like unevaluatedProperties, unevaluatedItems, contentEncoding, contentMediaType, and contentSchema.
OAS 3.2.0 Features:
The latest OAS version introduces several capabilities that oastools fully supports: the $self document identity URI, the QUERY HTTP method for complex queries, additionalOperations for custom HTTP methods, pathItems reusability via components (OAS 3.1+), and reusable mediaTypes in components.
The Overlay Specification v1.0.0 defines a document format for transforming OpenAPI descriptions while remaining separate from the source documents. oastools provides native overlay support through its dedicated overlay package.
The specification defines an overlay document structure with a required overlay version field, info metadata, an optional extends URL pointing to the target OpenAPI document, and an actions array containing transformation instructions.
Action Types:
The update action merges objects and appends to arrays at the target location. When targeting an object, properties are merged with overlay values taking precedence. When targeting an array, the update value is appended.
The remove action deletes nodes at the target location. When set to true, the matched nodes are removed from the document.
JSONPath Implementation:
oastools implements JSONPath per RFC 9535 for targeting nodes within OpenAPI documents. Supported features include root navigation ($), child access (dot and bracket notation), wildcards (* for all children), array indices (positive and negative), recursive descent (..), simple filter expressions ([?(@.property == value)]), compound filters with logical operators, and comparison operators (==, !=, <, >, <=, >=).
oastools targets Go 1.25+ and leverages language features accordingly. The toolkit uses generics for type-safe operations where appropriate, Go 1.24+ benchmark patterns with b.Loop() for accurate performance measurement, and standard library patterns for HTTP handling that integrate with net/http. The generator package produces code compatible with Go 1.18+ when using generics for optional types.
The toolkit implements or references several IETF RFCs. RFC 9535 (JSONPath) provides the query language for overlay targeting. RFC 7636 (PKCE) is implemented in OAuth2 code generation for secure authorization flows. RFC 6749 (OAuth 2.0) is the foundation for security scheme code generation. RFC 3986 (URIs) governs reference resolution and URL handling. RFC 6570 (URI Templates) underlies path parameter serialization.
oastools comprises twelve public packages, each with a focused responsibility and clear integration points.
oastools/
├── parser/ # Parse OAS documents from files, URLs, readers, or bytes
├── validator/ # Validate documents against their declared OAS version
├── fixer/ # Automatically fix common validation errors
├── httpvalidator/ # Runtime HTTP request/response validation
├── converter/ # Convert between OAS versions (2.0 ↔ 3.x)
├── joiner/ # Merge multiple OAS documents with collision handling
├── overlay/ # Apply OpenAPI Overlay transformations
├── differ/ # Compare documents, detect breaking changes
├── generator/ # Generate Go client/server code with security support
├── builder/ # Programmatically construct OAS documents
├── walker/ # Traverse OAS documents with typed handlers and flow control
├── oaserrors/ # Structured error types for programmatic handling
└── internal/ # Internal utilities (not public API)
├── mcpserver/ # MCP server exposing all capabilities over stdio
├── httputil/ # HTTP constants and validation
├── severity/ # Issue severity levels
├── issues/ # Unified issue reporting
├── schemautil/ # Schema utilities
├── jsonpath/ # JSONPath RFC 9535 implementation
├── corpusutil/ # Test corpus management
└── testutil/ # Test helpers
flowchart TB
subgraph Input["📥 Input Sources"]
File[File Path]
URL[URL]
Reader[io.Reader]
Bytes[Byte Slice]
end
subgraph Core["🔧 Core Processing"]
Parser[parser<br/>ParseResult]
Validator[validator]
Fixer[fixer]
Converter[converter]
end
subgraph Transform["🔄 Transformation"]
Joiner[joiner]
Overlay[overlay]
Differ[differ]
Walker[walker]
end
subgraph Output["📤 Output"]
Generator[generator<br/>Go Code]
Builder[builder<br/>OAS Document]
HTTPValidator[httpvalidator<br/>Runtime Validation]
end
subgraph Integration["🌐 Integration"]
MCPServer[MCP Server<br/>AI Tooling]
end
subgraph Shared["🔗 Shared"]
OASErrors[oaserrors]
end
File --> Parser
URL --> Parser
Reader --> Parser
Bytes --> Parser
Parser --> Validator
Parser --> Fixer
Parser --> Converter
Parser --> Joiner
Parser --> Overlay
Parser --> Differ
Parser --> Walker
Parser --> Generator
Parser --> HTTPValidator
Parser --> MCPServer
Builder --> Parser
OASErrors -.-> Core
OASErrors -.-> Transform
OASErrors -.-> Output
style Parser fill:#4db6ac,color:#000
style OASErrors fill:#ff8a65,color:#000
style MCPServer fill:#7986cb,color:#000
The packages form a coherent processing pipeline. The parser sits at the foundation, providing ParseResult structures consumed by all other packages. The validator depends on parser output for structural and semantic validation. The fixer uses parser output and can optionally leverage validator feedback for targeted fixes. The converter transforms parser output between OAS versions. The joiner combines multiple ParseResult instances into a unified document. The overlay applies transformations to parser output using JSONPath targeting. The differ compares two ParseResult instances to detect changes. The walker traverses parser output with typed handlers for analysis, mutation, and filtering. The generator produces Go code from parser output. The builder constructs documents programmatically, producing output compatible with parser structures. The httpvalidator uses parser output to validate runtime HTTP traffic. The oaserrors package provides error types used throughout all other packages.
A critical feature is format preservation across the pipeline. The parser detects source format (JSON or YAML) from file extension or content inspection and stores it in ParseResult.SourceFormat. This format flows through converter, joiner, and fixer operations, ensuring output matches input format. When joining multiple documents, the first document's format determines output format.
oastools packages are designed for seamless composition. Each package's result type provides a ToParseResult() method, enabling fluid pipelines without manual rewrapping:
result, err := parser.ParseWithOptions(parser.WithFilePath("spec.yaml"))
if err != nil { return err }
// Chain through the entire toolchain without losing context
validated, err := validator.ValidateWithOptions(validator.WithParsed(*result))
if err != nil { return err }
fixed, err := fixer.FixWithOptions(fixer.WithParsed(*validated.ToParseResult()))
if err != nil { return err }
converted, err := converter.ConvertWithOptions(
converter.WithParsed(*fixed.ToParseResult()),
converter.WithTargetVersion("3.1.0"),
)
if err != nil { return err }
joined, err := joiner.JoinWithOptions(
joiner.WithParsed(*converted.ToParseResult(), *other.ToParseResult()),
)
if err != nil { return err }| Package | Result Type | Provides ToParseResult() |
|---|---|---|
| validator | ValidationResult |
v1.41.0 |
| fixer | FixResult |
v1.41.0 |
| converter | ConversionResult |
v1.40.0 |
| joiner | JoinResult |
v1.40.0 |
| overlay | ApplyResult |
v1.41.0 |
This pattern eliminates boilerplate and preserves metadata (source path, OAS version, parse options) throughout the pipeline.
Links: pkg.go.dev | Deep Dive
The parser package forms the foundation of oastools, providing comprehensive parsing for OpenAPI documents across all supported versions.
The parser offers automatic version detection by examining the openapi or swagger field to determine version and select appropriate parsing strategy. It supports format detection through file extension inspection, content analysis (JSON starts with { or [), and falls back to YAML when uncertain. Multiple input sources are supported, including local file paths, remote URLs (with security controls), io.Reader implementations, and raw byte slices.
Reference handling is central to OpenAPI processing. The parser supports three reference types with distinct security profiles.
Local references (#/components/schemas/User) point within the same document and are always resolved. File references (./common.yaml#/schemas/Error) point to external files and are resolved with path traversal protection. HTTP references (https://example.com/schemas.yaml) point to remote URLs and require explicit opt-in via WithResolveHTTPRefs(true).
Circular Reference Handling:
When circular references are detected, the $ref node remains unresolved (preserving the original reference), a warning is added to result.Warnings, and the document remains valid for most operations. Detection triggers when a $ref points to an ancestor in the resolution path or when resolution depth exceeds MaxRefDepth.
Configurable limits protect against resource exhaustion attacks.
| Limit | Default | Description |
|---|---|---|
MaxRefDepth |
100 | Maximum nested $ref resolution depth |
MaxCachedDocuments |
100 | Maximum external documents to cache |
MaxFileSize |
10MB | Maximum file size for external references |
When parsing JSON input, the parser automatically uses an optimized fast-path that bypasses YAML AST overhead. This provides dramatic performance improvements for JSON specifications.
Automatic Triggering Conditions:
The fast-path activates when all conditions are met:
- ✅ Input is detected as JSON format
- ✅ Source map building is disabled (
WithSourceMap(false)) - ✅ Order preservation is disabled (
WithPreserveOrder(false))
Performance Improvements:
| Metric | Standard Path | JSON Fast-Path | Improvement |
|---|---|---|---|
| Parse time (large specs) | ~2.5s | ~0.3s | ~88% reduction |
| Memory allocation | ~750MB | ~50MB | ~93% reduction |
Why This Matters:
The yaml.v4 library builds a complete Abstract Syntax Tree with comprehensive token tracking. While necessary for YAML features (anchors, aliases, multiline strings), this is wasteful for JSON input where encoding/json is more efficient.
// Automatically uses fast-path (JSON input, no source map)
result, err := parser.ParseWithOptions(
parser.WithBytes(jsonData),
)
// Bypasses fast-path (source map requires YAML AST tracking)
result, err := parser.ParseWithOptions(
parser.WithBytes(jsonData),
parser.WithSourceMap(true),
)Functional Options Pattern:
result, err := parser.ParseWithOptions(
parser.WithFilePath("api.yaml"),
parser.WithResolveRefs(true),
parser.WithSourceMap(true),
)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Parsed %s, version %s\n", result.SourcePath, result.OASVersion)Struct-Based Pattern:
p := parser.New()
p.ResolveRefs = true
p.ValidateStructure = true
result1, _ := p.Parse("api1.yaml")
result2, _ := p.Parse("api2.yaml")The ParseResult type contains all parsed information.
type ParseResult struct {
// Document contains the parsed document (version-specific type)
Document any
// Version-specific accessors (methods, not fields)
// doc2, ok := result.OAS2Document() // Returns (*OAS2Document, bool)
// doc3, ok := result.OAS3Document() // Returns (*OAS3Document, bool)
// Metadata
Version string // Raw version string from document
OASVersion OASVersion // Detected version (e.g., "3.1.0")
SourcePath string // Source file path
SourceFormat SourceFormat // JSON or YAML
// Optional features
SourceMap *SourceMap // Line/column mapping (if enabled)
Warnings []string // Non-fatal warnings
Errors []error // Parse errors
}All parser types include generated DeepCopy() methods for safe mutation.
original, _ := result.OAS3Document()
copy := original.DeepCopy()
copy.Info.Title = "Modified API"
// original.Info.Title unchangedVendor extension extraction (x-* fields) now uses a streaming fast-path. A bytes.Contains check for "x- is performed before any JSON parsing, eliminating allocations entirely when no extensions are present. This optimization provides a 15x speedup for the common case (most specifications have few or no vendor extensions at the document level).
Reference resolution previously used a map → JSON bytes → struct roundtrip, which doubled peak memory during ResolveRefs=true. A new code-generated decodeFromMap approach decodes map[string]any values directly to typed structs for all 29 OAS types, eliminating the intermediate []byte allocation.
A companion ShallowCopy optimization on the RefResolver skips deep copy for non-circular references. When circular references are detected, the resolver automatically falls back to a full deep copy to avoid Go pointer cycles. Together these changes significantly reduce memory usage when resolving references in large specifications.
Unlike JSON marshal/unmarshal approaches, DeepCopy() preserves type information for polymorphic fields like Schema.Type (which may be string or []string in OAS 3.1+), version-specific semantics such as ExclusiveMinimum representation, and all x-* extension fields.
The DocumentAccessor interface provides version-agnostic access to common document fields across OAS 2.0 and OAS 3.x documents, eliminating the need for version-specific type switches.
result, _ := parser.ParseWithOptions(parser.WithFilePath("api.yaml"))
accessor := result.AsAccessor()
// Works identically for OAS 2.0 and 3.x
for path := range accessor.GetPaths() {
fmt.Println("Path:", path)
}
for name := range accessor.GetSchemas() {
fmt.Println("Schema:", name)
}
fmt.Println("Ref prefix:", accessor.SchemaRefPrefix())Available Methods:
| Method | OAS 2.0 Source | OAS 3.x Source |
|---|---|---|
GetInfo() |
doc.Info |
doc.Info |
GetPaths() |
doc.Paths |
doc.Paths |
GetSchemas() |
doc.Definitions |
doc.Components.Schemas |
GetSecuritySchemes() |
doc.SecurityDefinitions |
doc.Components.SecuritySchemes |
GetParameters() |
doc.Parameters |
doc.Components.Parameters |
GetResponses() |
doc.Responses |
doc.Components.Responses |
GetVersion() |
doc.OASVersion |
doc.OASVersion |
SchemaRefPrefix() |
#/definitions/ |
#/components/schemas/ |
This abstraction is particularly useful for tooling that needs to operate on documents regardless of their OAS version.
Key document types (OAS2Document, OAS3Document, Schema, ParseResult) provide Equals() methods for deep structural comparison:
if doc1.Equals(doc2) {
fmt.Println("Documents are structurally identical")
}This is useful for detecting changes, caching decisions, and test assertions.
The MarshalOrderedJSON() and MarshalOrderedYAML() methods on *ParseResult produce deterministic output by preserving key order. This ensures:
- Reproducible diffs between versions
- Consistent output for CI/CD pipelines
- Predictable test snapshots
Links: pkg.go.dev | Deep Dive
The validator package ensures OpenAPI documents conform to their declared specification version, catching structural errors and semantic violations.
Structural Validation verifies required fields are present, types are correct per specification, format constraints are satisfied, and reference targets exist.
Semantic Validation ensures operationIds are unique across the document, HTTP status codes are valid, parameter names are unique per location, and security scheme references exist in components.
Strict Mode performs additional checks including flagging non-standard HTTP status codes, requiring at least one success response (2xx) per operation, and detecting deprecated feature usage.
// Functional options with file path
result, err := validator.ValidateWithOptions(
validator.WithFilePath("api.yaml"),
validator.WithStrictMode(true),
)
// Pre-parsed for performance (31x faster)
parsed, _ := parser.ParseWithOptions(parser.WithFilePath("api.yaml"))
result, err := validator.ValidateWithOptions(
validator.WithParsed(*parsed),
validator.WithStrictMode(true),
)
if !result.Valid {
for _, e := range result.Errors {
fmt.Printf("Error at %s: %s\n", e.Path, e.Message)
}
}type ValidationResult struct {
Valid bool // Overall validity
Errors []ValidationError // Errors (spec violations)
Warnings []ValidationError // Warnings (best practice)
ErrorCount int
WarningCount int
Version string
OASVersion parser.OASVersion
}
type ValidationError struct {
Path string // JSON path to error location
Message string // Human-readable description
Severity severity.Severity // Error, Warning, or Info
SpecRef string // URL to relevant spec section
Line int // Line number (if source map enabled)
Column int // Column number (if source map enabled)
File string // File path (if source map enabled)
OperationContext *issues.OperationContext // API operation context (v1.46.0+)
}When parsing with WithSourceMap(true), validation errors include precise location information.
parsed, _ := parser.ParseWithOptions(
parser.WithFilePath("api.yaml"),
parser.WithSourceMap(true),
)
result, _ := validator.ValidateWithOptions(
validator.WithParsed(*parsed),
)
for _, e := range result.Errors {
fmt.Printf("%s:%d:%d: %s\n", e.File, e.Line, e.Column, e.Message)
}The --validate-structure CLI flag controls parser validation behavior, enabling strict structural validation during parsing.
Validation errors now include operation context, making it easy to identify which API endpoint triggered each error. The OperationContext field provides the HTTP method, path, and operationId.
result, _ := validator.ValidateWithOptions(
validator.WithParsed(*parsed),
)
for _, e := range result.Errors {
if e.OperationContext != nil {
fmt.Printf("%s %s (%s): %s\n",
e.OperationContext.Method,
e.OperationContext.Path,
e.OperationContext.OperationID,
e.Message)
}
}
// Output: GET /users/{userId} (getUser): missing path parameter "userId"Links: pkg.go.dev | Deep Dive
The fixer package automatically corrects common validation errors, reducing manual intervention in API specification maintenance.
Missing Path Parameters (FixTypeMissingPathParameter): When a path template contains variables like /users/{userId} but the operation lacks a corresponding parameter declaration, the fixer adds one. Type inference can be enabled to assign appropriate types based on naming conventions.
Invalid Schema Names (FixTypeRenamedGenericSchema): Schemas with names containing URL-encoding-required characters (such as Response[User] from code generators) are renamed using configurable strategies. All $ref values throughout the document are updated accordingly.
Unused Schemas (FixTypePrunedUnusedSchema): Schema definitions not referenced anywhere in the document are removed, cleaning up orphaned definitions.
Empty Paths (FixTypePrunedEmptyPath): Path items with no HTTP operations (only parameters or extensions) are removed.
Missing Reference Targets (FixTypeStubMissingRef, v1.46.0+): When a $ref points to a non-existent schema or response definition, the fixer creates a stub placeholder to prevent validation errors. Stub descriptions are configurable via WithStubConfig() or WithStubResponseDescription().
For performance, only FixTypeMissingPathParameter is enabled by default. Schema renaming and pruning involve expensive operations (walking all references, computing unused schemas) that can significantly slow processing of large specifications.
When enabled, the fixer infers parameter types from naming conventions.
| Pattern | Inferred Type | Format |
|---|---|---|
*id, *Id, *ID |
integer | - |
*uuid, *guid |
string | uuid |
| Everything else | string | - |
When fixing invalid schema names, several strategies are available.
| Strategy | Example Input | Example Output |
|---|---|---|
GenericNamingUnderscore |
Response[User] |
Response_User_ |
GenericNamingOf |
Response[User] |
ResponseOfUser |
GenericNamingFor |
Response[User] |
ResponseForUser |
GenericNamingFlattened |
Response[User] |
ResponseUser |
GenericNamingDot |
Response[User] |
Response.User |
// Enable specific fixes
result, err := fixer.FixWithOptions(
fixer.WithFilePath("api.yaml"),
fixer.WithEnabledFixes(
fixer.FixTypeMissingPathParameter,
fixer.FixTypeRenamedGenericSchema,
fixer.FixTypePrunedUnusedSchema,
),
fixer.WithInferTypes(true),
fixer.WithGenericNaming(fixer.GenericNamingOf),
)
fmt.Printf("Applied %d fixes\n", result.FixCount)
for _, fix := range result.Fixes {
fmt.Printf(" %s at %s\n", fix.Type, fix.Path)
}The fixer detects duplicate operationId values and automatically generates unique replacements, preventing spec validation failures.
Enum values specified as comma-separated strings are automatically expanded to proper typed arrays.
For performance-critical scenarios, WithMutableInput(true) skips the defensive deep copy of the input document. This is particularly useful when chaining multiple fix passes.
When to Use:
- ✅ Chaining multiple fixer passes (the first pass already creates a fresh copy)
- ✅ Memory efficiency is critical for large specifications
- ✅ You've already copied the document for your own mutations
Warning: FixWithOptions.
// First pass: creates a defensive copy (default behavior)
pass1, _ := fixer.FixWithOptions(
fixer.WithParsed(*parseResult),
fixer.WithEnabledFixes(fixer.FixTypeMissingPathParameter),
)
// Second pass: skip copy since we already own pass1's document
pass2, _ := fixer.FixWithOptions(
fixer.WithParsed(*pass1.ToParseResult()),
fixer.WithMutableInput(true), // Skip defensive copy
fixer.WithEnabledFixes(fixer.FixTypePrunedUnusedSchema),
)Performance: Typical memory savings of 10-30% for large specifications during fix operations.
Links: pkg.go.dev | Deep Dive
The converter package transforms OpenAPI documents between versions, handling the significant structural differences between OAS 2.0 and OAS 3.x.
| From | To | Notes |
|---|---|---|
| OAS 2.0 | OAS 3.0.x | Full upgrade with structural transformation |
| OAS 2.0 | OAS 3.1.x | Includes JSON Schema 2020-12 alignment |
| OAS 3.x | OAS 2.0 | Downgrade with potential feature loss |
| OAS 3.0.x | OAS 3.1.x | Version update within 3.x family |
| OAS 3.1.x | OAS 3.0.x | Version downgrade with schema adjustments |
OAS 2.0 → OAS 3.x:
The conversion handles structural changes between versions. The host, basePath, and schemes fields become the servers array. The consumes/produces fields and body parameter combine into requestBody with content map. The securityDefinitions becomes components/securitySchemes with restructured OAuth2 flows. The definitions section becomes components/schemas.
OAS 3.x → OAS 2.0:
Downgrade conversions handle feature reduction. Multiple servers collapse to host and basePath. The requestBody becomes a body parameter. Features without OAS 2.0 equivalents (callbacks, links) generate warnings.
Enhanced Downgrade Detection (v1.49.0+):
The converter now detects additional OAS 3.x features that cannot be faithfully represented in OAS 2.0, reporting them as issues with appropriate severity levels:
| Feature | Severity | Reason |
|---|---|---|
| Webhooks (3.1+) | Critical | No OAS 2.0 equivalent |
| Server variables | Warning | Extracted but incompatible |
| Multiple servers | Warning | Only first server used |
| Callbacks | Critical | No OAS 2.0 equivalent |
| Links | Warning | No OAS 2.0 equivalent (not yet detected -- planned) |
Conversions may produce issues at different severity levels.
Critical: The conversion cannot be completed accurately, such as when incompatible features block conversion.
Warning: Information may be lost, such as when multiple servers are collapsed to one or callbacks are removed.
Info: Structural changes were applied, such as when a security scheme was restructured.
result, err := converter.ConvertWithOptions(
converter.WithFilePath("swagger.yaml"),
converter.WithTargetVersion("3.1.0"),
)
for _, issue := range result.Issues {
fmt.Printf("[%s] %s: %s\n", issue.Severity, issue.Path, issue.Message)
}Links: pkg.go.dev | Deep Dive
The joiner package merges multiple OpenAPI documents into a single unified specification, handling collisions and maintaining referential integrity.
When joining documents, name collisions may occur in schemas, paths, or other components. The joiner provides configurable strategies.
| Strategy | Behavior |
|---|---|
StrategyFailOnCollision |
Error immediately on any collision (default) |
StrategyAcceptLeft |
Keep the first (left) definition |
StrategyAcceptRight |
Keep the last (right) definition |
StrategyRenameLeft |
Rename conflicting item from left document |
StrategyRenameRight |
Rename conflicting item from right document |
StrategyDeduplicateEquivalent |
Keep one if structurally identical, error if different |
StrategyFailOnPaths |
Error only on path collisions, accept others |
The StrategyDeduplicateEquivalent strategy performs deep structural comparison. Two schemas are considered equivalent if they have identical types, properties, required fields, and constraints. When equivalent schemas are found, one is kept and all references are updated to point to the surviving definition. Empty schemas (those with no properties, type, or constraints) are correctly preserved during deduplication rather than being collapsed (fixed in v1.46.2).
When schemas are renamed (via StrategyRenameLeft or StrategyRenameRight), the joiner automatically updates all $ref values throughout the merged document. This includes references in other schemas, request bodies, responses, parameters, and anywhere else references may appear.
Arrays like servers, security, and tags are merged according to configurable strategies.
config := joiner.DefaultConfig()
config.MergeArrays = true // Combine server, security, and tag arraysThe joiner integrates with the overlay package for transformations at different stages.
Pre-Join Overlays are applied to each input document before joining.
Post-Join Overlays are applied to the merged result.
result, err := joiner.JoinWithOptions(
joiner.WithFilePaths("api1.yaml", "api2.yaml"),
joiner.WithPreJoinOverlayFile("standardize.yaml"),
joiner.WithPostJoinOverlayFile("finalize.yaml"),
)When schemas collide during joining, simple source-based renaming (e.g., User_users) can produce unclear names that obscure the schema's purpose. Operation-aware renaming traces schemas back to their originating operations, enabling semantic names like CreateUserRequest or GetPetResponse that reflect how schemas are actually used.
Enabling Operation Context:
result, err := joiner.JoinWithOptions(
joiner.WithFilePaths("users.yaml", "orders.yaml"),
joiner.WithSchemaStrategy(joiner.StrategyRenameRight),
joiner.WithOperationContext(true),
joiner.WithRenameTemplate("{{.OperationID | pascalCase}}{{.Name}}"),
)Reference Graph Building:
When WithOperationContext(true) is enabled, the joiner builds a reference graph that traces schema relationships:
- Direct references - Schemas referenced directly by operations (request bodies, responses, parameters)
- Indirect references - Schemas referenced through intermediate schemas (e.g.,
OrderreferencesAddress) - Lineage resolution - Traverses the graph to find all operations that ultimately use each schema
This graph enables rename templates to access operation context even for deeply nested schemas.
Template Functions:
| Category | Functions | Description |
|---|---|---|
| Path | pathSegment, pathResource, pathLast, pathClean |
Extract and transform API path components |
| Case | pascalCase, camelCase, snakeCase, kebabCase |
Transform string casing |
| Tag | firstTag, joinTags, hasTag |
Work with operation tags |
| Conditional | default, coalesce |
Fallback value selection |
Template Examples:
// Use operationId when available, fall back to path resource
"{{coalesce .OperationID (pathResource .Path) .Source | pascalCase}}{{.Name}}"
// Include usage type for clarity
"{{.OperationID | pascalCase}}{{.UsageType | pascalCase}}{{.Name}}"
// Path-based naming when operationIds are inconsistent
"{{pathResource .Path | pascalCase}}{{.Name}}"Primary Operation Policy:
When a schema is referenced by multiple operations, the PrimaryOperationPolicy determines which operation provides context:
| Policy | Behavior |
|---|---|
PolicyFirstEncountered |
Uses the first operation found during traversal (default) |
PolicyMostSpecific |
Prefers operations with operationId, then tags |
PolicyAlphabetical |
Sorts by path+method and uses first alphabetically |
joiner.WithPrimaryOperationPolicy(joiner.PolicyMostSpecific)Deep Dive: For comprehensive
RenameContextdocumentation including all available fields, aggregate context for shared schemas, and advanced template patterns, see the Joiner Deep Dive.
result, err := joiner.JoinWithOptions(
joiner.WithFilePaths("users.yaml", "orders.yaml", "products.yaml"),
joiner.WithPathStrategy(joiner.StrategyAcceptLeft),
joiner.WithSchemaStrategy(joiner.StrategyDeduplicateEquivalent),
)
fmt.Printf("Joined documents into %d paths\n",
result.Stats.PathCount)Collision messages now include source file names for easier debugging when joining multiple specs.
For advanced use cases, custom collision handlers enable programmatic control over collision resolution. Handlers receive full context about each collision and can return custom resolution actions.
Collision Context:
type CollisionContext struct {
Type CollisionType // schema, path, webhook, etc.
Name string // The colliding name (e.g., "User")
JSONPath string // Full path (e.g., "$.components.schemas.User")
LeftSource string // Source file for left document
LeftValue any // The left component (*parser.Schema, etc.)
RightSource string // Source file for right document
RightValue any // The right component
ConfiguredStrategy CollisionStrategy // Default strategy that would apply
}Resolution Actions:
| Action | Behavior |
|---|---|
ResolutionContinue |
Defer to configured strategy (observe-only) |
ResolutionAcceptLeft |
Keep the left (base) value |
ResolutionAcceptRight |
Keep the right (incoming) value |
ResolutionRename |
Rename the right value (schemas only) |
ResolutionDeduplicate |
Treat colliding values as equivalent |
ResolutionFail |
Abort the join with an error |
ResolutionCustom |
Use a caller-provided merged value |
Usage Pattern:
result, err := joiner.JoinWithOptions(
joiner.WithFilePaths("base.yaml", "overlay.yaml"),
joiner.WithCollisionHandler(func(collision joiner.CollisionContext) (joiner.CollisionResolution, error) {
// Log all collisions for auditing
log.Printf("Collision: %s %s", collision.Type, collision.Name)
// Custom logic for schema collisions
if collision.Type == joiner.CollisionTypeSchema {
merged := customMergeLogic(collision.LeftValue, collision.RightValue)
return joiner.UseCustomValue(merged), nil
}
// Defer to strategy for other types
return joiner.ContinueWithStrategy(), nil
}),
)Use Cases:
- Semantic schema deduplication with custom logic
- Collision detection and auditing pipelines
- Domain-specific resolution (e.g., API versioning strategies)
Links: pkg.go.dev | Deep Dive
The overlay package implements the OpenAPI Overlay Specification v1.0.0, enabling declarative transformations of OpenAPI documents.
An overlay document contains metadata and a sequence of actions.
overlay: "1.0.0"
info:
title: Production Configuration
version: "1.0.0"
extends: openapi.yaml # Optional: target document
actions:
- target: $.info
update:
x-environment: production
- target: $.servers[?(@.description == 'Development')]
remove: trueUpdate Actions merge content at the target location.
When updating objects, properties from the overlay are merged with the target, with overlay values taking precedence for conflicting keys.
When updating arrays, the update value is appended to the target array.
Remove Actions delete nodes at the target location.
actions:
- target: $.paths['/internal/*']
remove: trueThe overlay package implements JSONPath per RFC 9535 with comprehensive feature support.
Supported Syntax:
| Expression | Description | Example |
|---|---|---|
$ |
Root object | $ |
.property |
Child access | $.info.title |
[name] |
Bracket notation | $.paths['/users'] |
* |
Wildcard | $.paths.* |
[0] |
Array index | $.servers[0] |
[-1] |
Negative index | $.tags[-1] |
[0:3] |
Slice | $.servers[0:3] |
.. |
Recursive descent | $..schema |
[?()] |
Filter expression | $.paths.*[?(@.deprecated == true)] |
Filter Operators:
Comparison operators include ==, !=, <, >, <=, and >=. Logical operators include && (and), || (or), and ! (not). Existence checks use @.property to test if property exists.
Preview changes without applying them.
dryRun, err := overlay.DryRunWithOptions(
overlay.WithSpecFilePath("openapi.yaml"),
overlay.WithOverlayFilePath("changes.yaml"),
)
for _, change := range dryRun.Changes {
fmt.Printf("Would %s %d nodes at %s\n",
change.Operation, change.MatchCount, change.Target)
}Enable strict mode to fail when targets match no nodes.
result, err := overlay.ApplyWithOptions(
overlay.WithSpecFilePath("openapi.yaml"),
overlay.WithOverlayFilePath("changes.yaml"),
overlay.WithStrictTargets(true),
)Links: pkg.go.dev | Deep Dive
The differ package compares OpenAPI documents to detect changes, with special focus on identifying breaking changes that may affect API consumers.
Simple Mode (ModeSimple): Reports all differences between documents without severity classification.
Breaking Mode (ModeBreaking): Categorizes differences by their impact on API consumers.
Changes are grouped by their location in the specification.
| Category | Examples |
|---|---|
| Endpoint | Path added/removed |
| Operation | Method added/removed/changed |
| Parameter | Parameter added/removed/modified |
| RequestBody | Request body changed |
| Response | Response added/removed/modified |
| Schema | Schema definition changed |
| Security | Security requirements changed |
| Server | Server configuration changed |
In breaking mode, changes are classified by severity.
Critical changes will break existing clients. Examples include removing endpoints, making optional parameters required, and changing parameter types.
Error changes are likely to cause problems. Examples include removing response schemas and changing required fields.
Warning changes may affect some clients. Examples include adding new required parameters with defaults and changing descriptions.
Info changes are additive or cosmetic. Examples include adding new optional endpoints and updating documentation.
result, err := differ.DiffWithOptions(
differ.WithSourceFilePath("v1.yaml"),
differ.WithTargetFilePath("v2.yaml"),
differ.WithMode(differ.ModeBreaking),
)
fmt.Printf("Changes: %d Breaking, %d Warning\n",
result.BreakingCount, result.WarningCount)
for _, change := range result.Changes {
if change.Severity == differ.SeverityCritical {
fmt.Printf("BREAKING: %s - %s\n", change.Path, change.Message)
}
}For comparing multiple versions, parse once and diff repeatedly.
v1, _ := parser.ParseWithOptions(parser.WithFilePath("v1.yaml"))
v2, _ := parser.ParseWithOptions(parser.WithFilePath("v2.yaml"))
v3, _ := parser.ParseWithOptions(parser.WithFilePath("v3.yaml"))
diff12, _ := differ.DiffWithOptions(
differ.WithSourceParsed(*v1),
differ.WithTargetParsed(*v2),
)
diff23, _ := differ.DiffWithOptions(
differ.WithSourceParsed(*v2),
differ.WithTargetParsed(*v3),
)Links: pkg.go.dev | Deep Dive
The generator package produces idiomatic Go code from OpenAPI specifications, with comprehensive support for authentication, file organization, and both client and server generation.
Client Mode generates an HTTP client with typed methods for each operation, request/response serialization, error handling, and authentication support.
Server Mode generates interface definitions that server implementations must satisfy, providing compile-time type safety for API contracts.
Types Mode generates Go structs from schema definitions, suitable for use across client and server implementations.
OpenAPI types map to Go types according to established conventions.
| OpenAPI Type | Go Type | Notes |
|---|---|---|
| string | string | |
| string (format: date-time) | time.Time | |
| string (format: uuid) | string | Can use uuid package |
| integer | int64 | |
| integer (format: int32) | int32 | |
| number | float64 | |
| number (format: float) | float32 | |
| boolean | bool | |
| array | []T | |
| object | struct or map[string]T | |
| oneOf/anyOf | interface{} | Or discriminated types |
The generator provides comprehensive authentication support based on RFC 6749 (OAuth 2.0) and RFC 7636 (PKCE).
API Key Authentication:
// Generated helper
func WithPetstoreAPIKey(key string) ClientOption {
return func(c *Client) error {
c.apiKey = key
return nil
}
}
// Usage
client, _ := NewClient(baseURL, WithPetstoreAPIKey("my-key"))HTTP Basic/Bearer:
func WithBasicAuth(username, password string) ClientOption { ... }
func WithBearerToken(token string) ClientOption { ... }OAuth2 Flows:
When GenerateOAuth2Flows is enabled, the generator produces complete OAuth2 clients for each security scheme.
// Generated OAuth2 client
type PetstoreAuthOAuth2Client struct {
Config OAuth2Config
AuthorizationURL string
TokenURL string
}
func (c *PetstoreAuthOAuth2Client) GetAuthorizationURL(state string) string { ... }
func (c *PetstoreAuthOAuth2Client) ExchangeCode(ctx context.Context, code string) (*OAuth2Token, error) { ... }
func (c *PetstoreAuthOAuth2Client) GetClientCredentialsToken(ctx context.Context) (*OAuth2Token, error) { ... }
func (c *PetstoreAuthOAuth2Client) RefreshToken(ctx context.Context, refreshToken string) (*OAuth2Token, error) { ... }PKCE Support (RFC 7636):
Authorization code flow includes PKCE for enhanced security.
verifier, challenge := GeneratePKCE()
authURL := oauth2Client.GetAuthorizationURLWithPKCE(state, challenge)
// After redirect...
token, err := oauth2Client.ExchangeCodeWithPKCE(ctx, code, verifier)OpenID Connect Discovery:
When GenerateOIDCDiscovery is enabled, an OIDC discovery client is generated.
discovery := NewOIDCDiscoveryClient(discoveryURL)
config, err := discovery.GetConfiguration(ctx)
// config contains authorization_endpoint, token_endpoint, etc.The generator produces a credential provider system for secure credential handling.
// Generated interfaces
type CredentialProvider interface {
GetCredential(ctx context.Context, scheme string) (string, error)
}
// Built-in implementations
type MemoryCredentialProvider struct { ... }
type EnvCredentialProvider struct { ... }
type CredentialChain struct { ... }
// Usage
provider := NewCredentialChain(
NewEnvCredentialProvider("API_KEY"),
NewMemoryCredentialProvider(credentials),
)
client, _ := NewClient(baseURL, WithCredentialProvider(provider))Server generation includes optional extensions for complete server implementation.
| Extension | File | Description |
|---|---|---|
ServerRouter |
server_router.go |
HTTP router with path matching |
ServerMiddleware |
server_middleware.go |
Request/response validation |
ServerBinder |
server_binder.go |
Type-safe parameter binding |
ServerResponses |
server_responses.go |
Typed response writers |
ServerStubs |
server_stubs.go |
Stub implementations for testing |
SecurityEnforce |
security_enforce.go |
Server-side security enforcement |
Large APIs can be split across multiple files for better organization and compilation times.
result, err := generator.GenerateWithOptions(
generator.WithFilePath("large-api.yaml"),
generator.WithMaxLinesPerFile(500),
generator.WithSplitByTag(true),
generator.WithClient(true),
)result, err := generator.GenerateWithOptions(
generator.WithFilePath("petstore.yaml"),
generator.WithPackageName("petstore"),
generator.WithClient(true),
generator.WithServer(true),
generator.WithServerAll(), // All server extensions
generator.WithOAuth2Flows(true),
generator.WithCredentialMgmt(true),
generator.WithOIDCDiscovery(true),
generator.WithReadme(true),
)
for _, file := range result.Files {
fmt.Printf("Generated %s (%d bytes)\n", file.Name, len(file.Content))
}Links: pkg.go.dev | Deep Dive
The builder package enables programmatic construction of OpenAPI documents, with reflection-based schema generation from Go types.
spec := builder.New(parser.OASVersion310)
spec.SetTitle("My API").
SetVersion("1.0.0").
SetDescription("A sample API").
AddServer("https://api.example.com",
builder.WithServerDescription("Production"))
spec.AddOperation(http.MethodGet, "/users",
builder.WithOperationID("listUsers"),
builder.WithSummary("List users"),
builder.WithResponseRef(http.StatusOK, spec.SchemaRef("UserList")),
)
doc, err := spec.BuildOAS3()Generate OpenAPI schemas from Go types automatically.
type User struct {
ID int64 `json:"id"`
Name string `json:"name" oas:"required"`
Email string `json:"email" oas:"format=email"`
CreatedAt time.Time `json:"created_at"`
Role string `json:"role" oas:"enum=admin|user|guest"`
}
spec := builder.New(parser.OASVersion310)
spec.RegisterType(User{})
// Generates:
// User:
// type: object
// required: [name]
// properties:
// id: { type: integer, format: int64 }
// name: { type: string }
// email: { type: string, format: email }
// created_at: { type: string, format: date-time }
// role: { type: string, enum: [admin, user, guest] }Go types map to OpenAPI schemas according to established conventions.
| Go Type | OpenAPI Type | Format |
|---|---|---|
| string | string | |
| int, int32 | integer | int32 |
| int64 | integer | int64 |
| float32 | number | float |
| float64 | number | double |
| bool | boolean | |
| []T | array | items: T |
| map[string]T | object | additionalProperties: T |
| struct | object | properties from fields |
| *T | nullable T | |
| time.Time | string | date-time |
Configurable naming strategies handle generic types and package prefixes.
| Strategy | Example Type | Result |
|---|---|---|
SchemaNamingDefault |
models.User |
models.User |
SchemaNamingPascalCase |
models.User |
ModelsUser |
SchemaNamingTypeOnly |
models.User |
User |
GenericNamingUnderscore |
Response[User] |
Response_User_ |
GenericNamingOf |
Response[User] |
ResponseOfUser |
| Custom | User-defined | Via WithSchemaNameFunc |
The ServerBuilder extends the standard builder to produce runnable HTTP servers directly from the fluent API. This enables a "spec-first" development workflow where OpenAPI documentation and implementation stay synchronized. Request validation is performed automatically using the httpvalidator package.
Creating a Server:
srv := builder.NewServerBuilder(parser.OASVersion320).
SetTitle("Pet Store API").
SetVersion("1.0.0")
srv.AddOperation(http.MethodGet, "/pets",
builder.WithHandler(func(ctx context.Context, req *builder.Request) builder.Response {
return builder.JSON(http.StatusOK, pets)
}),
builder.WithResponse(http.StatusOK, []Pet{}),
)
result, _ := srv.BuildServer()
http.ListenAndServe(":8080", result.Handler)Key Capabilities:
| Capability | Description |
|---|---|
| Request Validation | Automatic validation of path/query/header parameters and request bodies |
| Response Helpers | JSON(), NoContent(), Error(), Redirect(), Stream() for consistent responses |
| Middleware Support | Chain middleware functions for auth, logging, etc. |
| Testing Utilities | NewTestRequest(), ServerTest(), StubHandler() for easy testing |
| Fluent ResponseBuilder | Set headers, cookies, and streaming responses |
Handler Registration:
// Inline registration
srv.AddOperation(http.MethodGet, "/pets",
builder.WithHandler(listPetsHandler),
builder.WithResponse(http.StatusOK, []Pet{}),
)
// Dynamic registration
srv.Handle(http.MethodGet, "/pets", listPetsHandler)
srv.HandleFunc(http.MethodGet, "/health", healthHandler)Operations without registered handlers return 501 Not Implemented at runtime.
When multiple types generate identical schemas, the builder consolidates them.
// Enable semantic deduplication via constructor option
spec := builder.New(parser.OASVersion310, builder.WithSemanticDeduplication(true))
spec.RegisterType(UserRequest{}) // Creates UserRequest schema
spec.RegisterType(UserResponse{}) // If identical, reuses UserRequestLinks: pkg.go.dev | Deep Dive
The httpvalidator package validates HTTP requests and responses against OpenAPI specifications at runtime, suitable for API gateways, middleware, and testing.
Request Validation covers path parameters with template matching, query parameters with type coercion, header parameters, cookie parameters, and request body schema validation.
Response Validation covers status code verification against documented responses, response header validation, and response body schema validation.
All OAS serialization styles are supported per the OpenAPI Specification.
| Style | Location | Example |
|---|---|---|
| simple | path, header | value or val1,val2 |
| form | query, cookie | ?ids=1,2,3 |
| matrix | path | ;id=5 |
| label | path | .blue.red |
| deepObject | query | ?filter[status]=active |
| spaceDelimited | query | ?ids=1%202%203 |
| pipeDelimited | query | ?ids=1|2|3 |
Creating a Validator:
parsed, _ := parser.ParseWithOptions(parser.WithFilePath("openapi.yaml"))
v, err := httpvalidator.New(parsed)
if err != nil {
log.Fatal(err)
}Validating Requests:
result, err := v.ValidateRequest(req)
if !result.Valid {
for _, e := range result.Errors {
fmt.Printf("Error: %s - %s\n", e.Path, e.Message)
}
}
// Access deserialized parameters
userID := result.PathParams["userId"]
limit := result.QueryParams["limit"]Validating Responses:
result, err := v.ValidateResponseData(req, statusCode, headers, body)
if !result.Valid {
log.Printf("Response validation failed: %v", result.Errors)
}The validator integrates naturally with HTTP middleware patterns.
func ValidationMiddleware(v *httpvalidator.Validator) func(http.Handler) http.Handler {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
result, _ := v.ValidateRequest(r)
if !result.Valid {
w.WriteHeader(http.StatusBadRequest)
json.NewEncoder(w).Encode(map[string]any{
"error": "Validation failed",
"details": result.Errors,
})
return
}
next.ServeHTTP(w, r)
})
}
}Enable strict mode for stricter validation.
v.StrictMode = trueIn strict mode, unknown query parameters cause validation errors, unknown headers (except standard HTTP headers) cause errors, unknown cookies cause errors, and undocumented response status codes cause errors.
Links: pkg.go.dev | Deep Dive
The walker package provides typed, handler-based traversal of OpenAPI documents, enabling analysis, mutation, validation, and filtering patterns.
The walker uses a handler-based approach where you register callbacks for specific node types. Each handler receives a pointer to the node (enabling mutation) and the JSON path to that node.
Flow Control:
| Action | Behavior |
|---|---|
Continue |
Process children and continue to siblings |
SkipChildren |
Skip descendants, continue to siblings |
Stop |
Halt traversal immediately |
The walker provides 19 typed handlers covering all OAS node types:
| Handler | Description |
|---|---|
WithDocumentHandler |
Root document (version-agnostic) |
WithOAS2DocumentHandler |
OAS 2.0 document |
WithOAS3DocumentHandler |
OAS 3.x document |
WithInfoHandler |
API metadata |
WithServerHandler |
Server definitions (3.x only) |
WithPathHandler |
Path entries with template |
WithOperationHandler |
HTTP operations |
WithParameterHandler |
Parameters |
WithRequestBodyHandler |
Request bodies (3.x only) |
WithResponseHandler |
Responses |
WithSchemaHandler |
All schemas (including nested) |
WithSecuritySchemeHandler |
Security schemes |
WithTagHandler |
Tags |
WithHeaderHandler |
Headers |
WithMediaTypeHandler |
Media types (3.x only) |
WithLinkHandler |
Links (3.x only) |
WithCallbackHandler |
Callbacks (3.x only) |
WithExampleHandler |
Examples |
WithExternalDocsHandler |
External documentation |
Analysis Pattern:
var stats struct {
Operations int
Schemas int
}
walker.Walk(result,
walker.WithOperationHandler(func(wc *walker.WalkContext, op *parser.Operation) walker.Action {
stats.Operations++
return walker.Continue
}),
walker.WithSchemaHandler(func(wc *walker.WalkContext, schema *parser.Schema) walker.Action {
stats.Schemas++
return walker.Continue
}),
)
fmt.Printf("Operations: %d, Schemas: %d\n", stats.Operations, stats.Schemas)Mutation Pattern:
walker.Walk(result,
walker.WithSchemaHandler(func(wc *walker.WalkContext, schema *parser.Schema) walker.Action {
if schema.Extra == nil {
schema.Extra = make(map[string]any)
}
schema.Extra["x-processed"] = true
return walker.Continue
}),
)Filtering Pattern:
walker.Walk(result,
walker.WithPathHandler(func(wc *walker.WalkContext, pi *parser.PathItem) walker.Action {
if strings.HasPrefix(wc.PathTemplate, "/internal") {
return walker.SkipChildren // Skip internal endpoints
}
return walker.Continue
}),
)The walker automatically detects circular schema references and provides notifications via WithSchemaSkippedHandler:
walker.Walk(result,
walker.WithMaxSchemaDepth(50), // WithMaxDepth is deprecated; prefer WithMaxSchemaDepth
walker.WithSchemaSkippedHandler(func(wc *walker.WalkContext, reason string, schema *parser.Schema) {
if reason == "cycle" {
fmt.Printf("Circular reference at: %s\n", wc.JSONPath)
}
}),
)The walker package enables several common patterns:
| Use Case | Handlers | Flow Control |
|---|---|---|
| API Statistics | Operation, Schema, Parameter | Continue |
| Security Audit | Operation, Schema, Path | Continue, Stop |
| Vendor Extensions | Schema, Operation, Path | Continue, SkipChildren |
| Public API Filter | Path, Operation | SkipChildren |
| Documentation Gen | Info, Server, Operation, Response | Continue |
| Reference Analysis | Schema, SchemaSkipped | Continue |
The walker has gained several powerful features:
- Reference Tracking -
WithRefHandler()andWithMapRefTracking()for comprehensive$refdetection - Parent Tracking -
WithParentTracking()provides type-safe ancestor access viaParentInfo - Post-Visit Hooks -
WithSchemaPostHandler(),WithOperationPostHandler(), etc. for bottom-up processing - Built-in Collectors -
CollectSchemas()andCollectOperations()reduce boilerplate
For comprehensive documentation, examples, and performance considerations, see the Walker Deep Dive.
Links: MCP Server Guide | Claude Code Plugin | Model Context Protocol
oastools includes a built-in Model Context Protocol (MCP) server that exposes all toolkit capabilities to AI-assisted development environments such as Claude Code, Cursor, and other MCP-compatible clients. The server communicates over stdio transport and is launched via the CLI.
oastools mcpThe MCP server provides 17 tools organized into two categories.
Core Tools (9 tools):
| Tool | Description |
|---|---|
validate |
Validate OAS documents with error/warning counts and JSON path locations |
parse |
Parse OAS with structural summary (title, version, path/operation/schema counts) |
fix |
Auto-fix common issues with dry-run support |
convert |
Convert between OAS versions with issue tracking |
diff |
Compare specs with breaking change detection and severity levels |
join |
Merge multiple specs with configurable collision strategies |
overlay_apply |
Apply Overlay documents using JSONPath expressions |
overlay_validate |
Validate Overlay document structure and JSONPath syntax |
generate |
Generate Go client/server/types code |
Walk Tools (8 tools):
| Tool | Description |
|---|---|
walk_operations |
Filter by method, path, tag, operationId, deprecated status |
walk_schemas |
Filter by name, type, component/inline location |
walk_parameters |
Filter by location, name, path pattern, method |
walk_responses |
Filter by status code, path, method |
walk_security |
Filter by security scheme name or type |
walk_paths |
Filter by path pattern with glob support |
walk_refs |
Query $ref references ranked by count with target filtering |
walk_headers |
Query response and component headers |
Pagination: All tools support offset/limit parameters (default limit: 100, maximum: 1000) for handling large specifications.
Group-By Aggregation: Most walk tools support a group_by parameter (all except walk_security) that returns distribution counts instead of individual items. For example, walk_operations with group_by=method returns a count of operations per HTTP method.
Detail Mode: Walk tools support a detail flag that returns full nested objects instead of summary tables (default limit: 25 items in detail mode).
Spec Caching: Parsed specifications are cached within MCP sessions with TTL-based expiration. File entries auto-invalidate on modification, URL entries expire based on configurable TTLs, and a background sweeper removes expired entries.
The MCP server is configured via environment variables, since the Go MCP SDK does not support initializationOptions. MCP clients set these via their env field in server configuration.
Cache Configuration:
| Variable | Default | Description |
|---|---|---|
OASTOOLS_CACHE_ENABLED |
true |
Enable/disable spec caching |
OASTOOLS_CACHE_MAX_SIZE |
10 |
Maximum cached specifications |
OASTOOLS_CACHE_FILE_TTL |
15m |
File spec expiration |
OASTOOLS_CACHE_URL_TTL |
5m |
URL-fetched spec expiration |
OASTOOLS_CACHE_CONTENT_TTL |
15m |
Inline content spec expiration |
OASTOOLS_CACHE_SWEEP_INTERVAL |
60s |
Background cleanup frequency |
Behavior Defaults:
| Variable | Default | Description |
|---|---|---|
OASTOOLS_WALK_LIMIT |
100 |
Default result limit |
OASTOOLS_WALK_DETAIL_LIMIT |
25 |
Detail mode result limit |
OASTOOLS_VALIDATE_STRICT |
false |
Enable strict validation |
OASTOOLS_VALIDATE_NO_WARNINGS |
false |
Suppress validation warnings |
OASTOOLS_JOIN_PATH_STRATEGY |
— | Default path collision strategy |
OASTOOLS_JOIN_SCHEMA_STRATEGY |
— | Default schema collision strategy |
The MCP server implements several security measures:
- Error sanitization — Filesystem paths are stripped from error messages to prevent information disclosure
- Output path sanitization — Generated output paths are validated against path traversal, with symlink checks
- SSRF protection — Blocks resolution of private, loopback, and link-local IP addresses (opt-out via
OASTOOLS_ALLOW_PRIVATE_IPS) - Input size bounds — Inline content limited to 10 MiB (configurable via
OASTOOLS_MAX_INLINE_SIZE) - Pagination safety — Limit parameter capped at 1000 (
OASTOOLS_MAX_LIMIT) - Join spec bounds — Maximum 20 specs per join operation (
OASTOOLS_MAX_JOIN_SPECS) - Package name validation — Generated package names validated against
^[a-z][a-z0-9_]*$
Links: pkg.go.dev
The oaserrors package provides structured error types that integrate with Go's standard error handling mechanisms.
| Type | Description | Sentinel |
|---|---|---|
ParseError |
YAML/JSON parsing failures | ErrParse |
ReferenceError |
$ref resolution failures |
ErrReference |
ValidationError |
Specification violations | ErrValidation |
ResourceLimitError |
Resource exhaustion | ErrResourceLimit |
ConversionError |
Version conversion failures | ErrConversion |
ConfigError |
Invalid configuration | ErrConfig |
| Sentinel | Matches | Condition |
|---|---|---|
ErrCircularReference |
ReferenceError |
IsCircular == true |
ErrPathTraversal |
ReferenceError |
IsPathTraversal == true |
result, err := parser.ParseWithOptions(parser.WithFilePath("api.yaml"))
if err != nil {
if errors.Is(err, oaserrors.ErrPathTraversal) {
log.Fatal("Security: path traversal blocked")
}
if errors.Is(err, oaserrors.ErrCircularReference) {
log.Println("Warning: circular reference detected")
// May still be usable
}
if errors.Is(err, oaserrors.ErrParse) {
log.Fatal("Failed to parse document")
}
}var refErr *oaserrors.ReferenceError
if errors.As(err, &refErr) {
fmt.Printf("Failed ref: %s (type: %s)\n", refErr.Ref, refErr.RefType)
if refErr.IsCircular {
fmt.Println("Circular reference detected")
}
}
var valErr *oaserrors.ValidationError
if errors.As(err, &valErr) {
fmt.Printf("Validation error at %s: %s\n", valErr.Path, valErr.Message)
if valErr.SpecRef != "" {
fmt.Printf("See: %s\n", valErr.SpecRef)
}
}All error types support chaining via the Cause field and Unwrap() method.
var refErr *oaserrors.ReferenceError
if errors.As(err, &refErr) {
if errors.Is(refErr.Cause, os.ErrNotExist) {
fmt.Println("Referenced file does not exist")
}
}Error and warning types in the builder, joiner, and overlay packages implement the HasLocation() and Location() methods for programmatic error handling with source context. This enables IDE-friendly error reporting and structured handling of non-fatal issues.
BuilderError:
var builderErr *builder.BuilderError
if errors.As(err, &builderErr) {
if builderErr.HasLocation() {
fmt.Printf("Error at %s: %s\n", builderErr.Location(), builderErr.Message)
// Output: Error at POST /users: duplicate operationId "createUser"
}
}JoinWarning:
for _, w := range result.StructuredWarnings {
if w.HasLocation() {
fmt.Printf("%s: %s\n", w.Location(), w.Message)
// Output: users.yaml:42:5: schema 'User' collision resolved
}
}ApplyWarning (Overlay):
for _, w := range result.StructuredWarnings {
if w.HasLocation() {
fmt.Printf("%s: %s\n", w.Location(), w.Message)
// Output: action[2]: target matched no nodes
}
}oastools includes comprehensive benchmarking infrastructure and has undergone targeted optimization to achieve significant performance improvements.
The most significant performance gain comes from the parse-once pattern. When the same document undergoes multiple operations, parsing once and passing the result to subsequent operations eliminates redundant work.
| Operation | Standard | Pre-Parsed | Speedup |
|---|---|---|---|
| Validate | 135 μs | 4.8 μs | 31x |
| Convert | 152 μs | 3.2 μs | 47x |
| Join (2 docs) | 110 μs | 732 ns | 150x |
| Diff | 280 μs | 12.7 μs | 81x |
| Fix | 140 μs | 2.8 μs | ~60x |
| Apply (overlay) | 120 μs | ~8 μs | ~11x |
Usage Pattern:
// Parse once
parsed, _ := parser.ParseWithOptions(parser.WithFilePath("api.yaml"))
// Reuse for multiple operations
valResult, _ := validator.ValidateWithOptions(validator.WithParsed(*parsed))
fixResult, _ := fixer.FixWithOptions(fixer.WithParsed(*parsed))
convResult, _ := converter.ConvertWithOptions(
converter.WithParsed(*parsed),
converter.WithTargetVersion("3.1.0"),
)Version 1.7.0 introduced optimized JSON marshaling that eliminates double-marshal patterns across all 29 custom JSON marshalers in the parser package.
| Improvement | Before | After |
|---|---|---|
| Performance | Baseline | 25-32% faster |
| Allocations | Baseline | 29-37% fewer |
Version 1.20.0 replaced JSON marshal/unmarshal with code-generated DeepCopy() methods.
| Improvement | Before | After |
|---|---|---|
| Deep copy speed | Baseline | ~37x faster |
| Type preservation | No | Yes |
| Memory efficiency | Baseline | Significantly better |
The httpvalidator package is optimized for high-throughput scenarios.
| Operation | Time | Memory | Allocations |
|---|---|---|---|
| Path matching (small spec) | 210 ns | 528 B | 8 |
| Path matching (large spec) | 502 ns | 528 B | 8 |
| With JSON body | 455 ns | 1.5 KB | 16 |
| Response validation | 110 ns | 256 B | 2 |
File-based benchmarks can vary ±50% due to I/O variance. For reliable regression detection, use I/O-isolated benchmarks.
Reliable Benchmarks:
| Package | Benchmark | Measures |
|---|---|---|
| parser | BenchmarkParseCore |
Parsing logic only |
| joiner | BenchmarkJoinParsed |
Joining logic only |
| validator | BenchmarkValidateParsed |
Validation logic only |
| fixer | BenchmarkFixParsed |
Fixing logic only |
| converter | BenchmarkConvertParsed* |
Conversion logic only |
| differ | BenchmarkDiff/Parsed |
Diffing logic only |
| walker | BenchmarkWalk/Parsed |
Walking logic only |
The parser and generator packages use sync.Pool to reduce GC pressure:
Marshal Buffer Pool (parser):
- Reuses
bytes.Bufferfor JSON/YAML marshaling - Up to 36% fewer allocations for large documents
- 78x faster buffer acquisition vs allocation
Template Buffer Pool (generator):
- Tiered pools (8KB/32KB/64KB) based on operation count
- Prevents oversized allocations during code generation
Design Decisions:
- All pools are internal (package-private)
- Reset-on-get pattern ensures clean state
- Size guards prevent memory leaks from oversized objects
- 7 planned pools were cut (YAGNI) due to use-after-put risks
Capacity decisions are data-driven from corpus analysis of 10 real-world OpenAPI specs (19,147 operations, 360,577 schemas).
The parser now automatically uses an optimized path for JSON input that bypasses YAML AST overhead.
| Metric | Standard Path | JSON Fast-Path | Improvement |
|---|---|---|---|
| Parse time (large specs) | ~2.5s | ~0.3s | ~88% reduction |
| Memory allocation | ~750MB | ~50MB | ~93% reduction |
The fast-path activates automatically when:
- ✅ Input is detected as JSON format
- ✅ Source map building is disabled
- ✅ Order preservation is disabled
A new internal pathutil package provides efficient incremental path building using push/pop semantics, eliminating allocations during recursive document traversal.
| Operation | fmt.Sprintf | PathBuilder | Improvement |
|---|---|---|---|
| Deep path building | ~1-2μs | ~200-300ns | ~6-8x faster |
| Path without String() | ~200-300ns | ~20-50ns | ~4-10x faster |
| SchemaRef building | ~30-50ns | ~5-10ns | ~5x faster |
The v1.48.1 release migrated the validator, fixer, builder, and joiner packages to use pathutil for all internal ref string building, reducing hot path allocations by ~5-15%.
The fixer's WithMutableInput(true) option eliminates defensive copying when chaining multiple fix passes:
| Scenario | Standard | WithMutableInput | Improvement |
|---|---|---|---|
| Chained fix passes | 2× copy | 1× copy | 50% memory |
| Large spec fixes | Baseline | 10-30% less memory | Significant |
Vendor extension extraction was optimized with a bytes.Contains pre-check for "x- before expensive JSON parsing. This eliminates allocations entirely for documents without vendor extensions.
| Scenario | Before | After | Improvement |
|---|---|---|---|
| No extensions (common case) | ~2,818 ns | ~186 ns | 15x faster |
| Allocations (no extensions) | Baseline | 0 | Zero-alloc |
Reference resolution previously used a map → JSON bytes → struct roundtrip that doubled peak memory. Code-generated decodeFromMap methods now decode map[string]any directly to typed structs for all 29 OAS types, eliminating the intermediate []byte allocation. Combined with a ShallowCopy optimization that skips deep copy for non-circular references, this significantly reduces memory usage when resolving references in large specifications.
The oastools test suite validates against a corpus of ten production APIs spanning diverse domains, sizes, and OAS versions.
| API | OAS Version | Size | Domain | Key Testing Focus |
|---|---|---|---|---|
| Microsoft Graph | 3.0.4 | 34 MB, ~18k ops | Enterprise | Largest spec, stress testing |
| Stripe | 3.0.0 | 2.5 MB, 900+ ops | FinTech | Polymorphic types, callbacks |
| GitHub | 3.0.3 | 424 KB, 600+ ops | Developer Tools | Extensive $ref linking |
| Plaid | 3.0.0 | 1.2 MB | FinTech | Multi-server, strict security |
| Discord | 3.1.0 | 2-5 MB | Communications | OAS 3.1 features, webhooks |
| DigitalOcean | 3.0.0 | 2.4 MB | Cloud | External $ref files, bundling |
| Google Maps | 3.0.3 | 500 KB | Geo/Mapping | Geo-coordinate parameters |
| US NWS | 3.0.3 | 800 KB | Public/Weather | JSON-LD extensions |
| Petstore | 2.0 | 20 KB | Reference | Baseline OAS 2.0 compatibility |
| Asana | 3.0.0 | 405 KB | Productivity | OAuth2, clean YAML structure |
The test corpus can be downloaded for local testing.
make corpus-downloadSpecifications are stored in testdata/corpus/ with consistent naming.
The corpus exercises key functionality across packages. Parser testing covers format detection (JSON and YAML), reference resolution (local and external), version detection (2.0 through 3.1), large document handling, and circular reference detection. Validator testing covers structural validation, semantic validation, strict mode validation, and source map integration. Converter testing covers OAS 2.0 to 3.x upgrade, OAS 3.x to 2.0 downgrade, and issue tracking. Joiner testing covers multi-document merging, collision handling, and reference rewriting. Differ testing covers breaking change detection and change categorization. Generator testing covers client generation, server generation, security code generation, and OAuth2 flow generation.
oastools provides a comprehensive command-line interface for all major operations.
Homebrew:
brew install erraggy/oastools/oastoolsGo Install:
go install github.com/erraggy/oastools/cmd/oastools@latestParse:
oastools parse openapi.yaml
oastools parse --resolve-refs openapi.yaml
oastools parse --source-map openapi.yamlValidate:
oastools validate openapi.yaml
oastools validate --strict openapi.yaml
oastools validate -q openapi.yaml # Quiet modeFix:
oastools fix openapi.yaml
oastools fix --infer openapi.yaml # With type inference
oastools fix --prune-unused openapi.yaml # Remove unused schemas
oastools fix -o fixed.yaml openapi.yaml # Output to fileConvert:
oastools convert -t 3.1.0 swagger.yaml
oastools convert -t 2.0 openapi.yaml # Downgrade
oastools convert -t 3.1.0 -o converted.yaml swagger.yamlJoin:
oastools join api1.yaml api2.yaml api3.yaml
oastools join --strategy accept-left *.yaml
oastools join -o combined.yaml users.yaml orders.yamlOverlay:
oastools overlay apply -s openapi.yaml changes.yaml
oastools overlay apply --dry-run -s openapi.yaml changes.yaml
oastools overlay apply --strict -s openapi.yaml changes.yamlDiff:
oastools diff v1.yaml v2.yaml
oastools diff --breaking v1.yaml v2.yaml # Breaking changes only
oastools diff --format json v1.yaml v2.yamlGenerate:
oastools generate -client -p petstore openapi.yaml
oastools generate -server -server-all -p petstore openapi.yaml
oastools generate -client -server -oauth2-flows -p petstore openapi.yaml
oastools generate -client -security-enforce -credential-mgmt -p petstore openapi.yamlWalk (v1.50.0+):
oastools walk operations openapi.yaml # List all operations
oastools walk operations --method GET openapi.yaml # Filter by method
oastools walk schemas --type object openapi.yaml # Filter schemas by type
oastools walk parameters --in query openapi.yaml # Filter by location
oastools walk responses --status 2xx openapi.yaml # Wildcard status codes
oastools walk security openapi.yaml # List security schemes
oastools walk paths --path '/pets/*' openapi.yaml # Glob pattern matchingWalk subcommands support --format (text/json/yaml), --detail for full output, --extension for vendor extension filtering, and --resolve-refs for $ref resolution.
MCP (v1.51.0+):
oastools mcp # Start MCP server over stdioThe MCP command launches a Model Context Protocol server that exposes all oastools capabilities as tools. See §15. MCP Server for details.
| Flag | Description |
|---|---|
-h, --help |
Show help |
-v, --version |
Show version |
-q, --quiet |
Suppress informational output |
--no-color |
Disable colored output |
oastools provides two complementary API styles for different use cases.
Best for one-off operations with explicit configuration.
result, err := parser.ParseWithOptions(
parser.WithFilePath("api.yaml"),
parser.WithResolveRefs(true),
parser.WithSourceMap(true),
)Advantages: Self-documenting, compile-time safety, easy to extend.
Best for batch processing with shared configuration.
p := parser.New()
p.ResolveRefs = true
p.ValidateStructure = true
for _, file := range files {
result, err := p.Parse(file)
// Process result
}Advantages: Reusable configuration, lower allocation overhead for multiple operations.
Best for pipeline processing where multiple operations apply to the same document.
parsed, _ := parser.ParseWithOptions(parser.WithFilePath("api.yaml"))
// All subsequent operations skip parsing
valResult, _ := validator.ValidateWithOptions(validator.WithParsed(*parsed))
fixResult, _ := fixer.FixWithOptions(fixer.WithParsed(*parsed))
genResult, _ := generator.GenerateWithOptions(
generator.WithParsed(*parsed),
generator.WithClient(true),
)Consistent error handling across all packages using oaserrors.
result, err := someOperation()
if err != nil {
// Check category with errors.Is
if errors.Is(err, oaserrors.ErrParse) {
// Handle parse error
}
// Extract details with errors.As
var refErr *oaserrors.ReferenceError
if errors.As(err, &refErr) {
fmt.Printf("Failed ref: %s\n", refErr.Ref)
}
return err
}oastools incorporates several security measures to protect against common vulnerabilities.
External file references are validated to prevent path traversal attacks.
resolver := parser.NewRefResolver("/base/path", 0, 0, 0)
// Attempting to resolve "../../../etc/passwd" will fail with ErrPathTraversalThe resolver ensures resolved paths remain within the allowed base directory, even on Windows with path variations.
Remote URL resolution is disabled by default and requires explicit opt-in.
result, err := parser.ParseWithOptions(
parser.WithFilePath("api.yaml"),
parser.WithResolveHTTPRefs(true), // Explicit opt-in required
)Configurable limits prevent resource exhaustion.
| Limit | Default | Purpose |
|---|---|---|
MaxRefDepth |
100 | Prevents stack overflow from deep/circular refs |
MaxCachedDocuments |
100 | Limits memory usage for external docs |
MaxFileSize |
10 MB | Prevents memory exhaustion from large files |
Generated OAuth2 code uses PKCE (RFC 7636) for authorization code flows, preventing authorization code interception attacks.
// Generated code includes PKCE support
verifier, challenge := GeneratePKCE()
authURL := oauth2Client.GetAuthorizationURLWithPKCE(state, challenge)Generated credential management systems avoid hardcoding secrets.
// Credential chain allows secure secret retrieval
provider := NewCredentialChain(
NewEnvCredentialProvider("API_KEY"),
NewVaultCredentialProvider(vaultClient),
)Version 1.52.0 introduced a comprehensive security audit addressing 7 High and 19 Medium severity findings across five attack surfaces.
MCP Server:
- Output path sanitization with
filepath.Clean,..traversal rejection, and symlink checks - SSRF protection blocking private, loopback, and link-local IP addresses (opt-out via
OASTOOLS_ALLOW_PRIVATE_IPS) - Input size bounds (10 MiB inline content limit)
- Pagination safety (limit capped at 1000)
- Error sanitization stripping filesystem paths from error messages
Parser & Resolver:
- Input size limit of 100 MiB (configurable via parser option)
- HTTP fetch response size wrapped with
io.LimitReader - Redirect safety with custom
CheckRedirectvalidation - Same-origin enforcement for relative reference resolution
HTTP Validator:
- Body size limits (10 MiB default, configurable via
WithMaxBodySize()) - Concurrent pattern cache replaced with
sync.Mapand 1000-entry size cap additionalProperties: falseenforcement for unexpected properties- Error sanitization using
%qformatting and 200-character truncation for user-supplied values
Generator:
- Path traversal prevention with
[a-z0-9_]allowlist andfilepath.Basesafety - Comment injection prevention through
cleanDescriptionsanitization - Generated clients default to
&http.Client{Timeout: 30 * time.Second} - OAuth2/OIDC URL scheme validation in generated code
- Discriminator JSON name escaping
Cross-Cutting:
- Symlink safety via
os.Lstatchecks before file writes - JSONPath recursion depth cap at 500
- Stdlib replacement sweep for hand-rolled form parsing
- Dependency update:
go-sdkv1.3.0 → v1.3.1 (case-sensitive JSON unmarshaling security patch)
oastools represents a comprehensive solution for OpenAPI tooling in the Go ecosystem. Its strengths lie in several key areas.
Complete OAS Coverage: Supporting versions 2.0 through 3.2.0 ensures compatibility with both legacy and cutting-edge specifications, including the latest JSON Schema 2020-12 alignment and streaming capabilities.
Native Overlay Support: First-class implementation of the OpenAPI Overlay Specification v1.0.0 enables declarative transformations that integrate throughout the toolkit.
Performance Optimization: The parse-once pattern, code-generated deep copy methods, JSON fast-path, and streaming extension extraction deliver 9-150x speedups for common workflows with up to 93% memory reduction for large JSON specifications.
Security-First Design: Comprehensive OAuth2, PKCE, and OIDC support in generated clients, combined with v1.52.0 security hardening across the MCP server, parser, validator, and generator, addresses both code generation security and runtime protection.
AI-Assisted Development: The built-in MCP server exposes all 17 tools over the Model Context Protocol, enabling AI development environments to query, validate, transform, and generate code from OpenAPI specifications with configurable caching and pagination.
Minimal Dependencies: Only go.yaml.in/yaml/v4, golang.org/x/text, golang.org/x/tools, and github.com/modelcontextprotocol/go-sdk are required, minimizing attack surface and build complexity.
Battle-Tested Quality: Validation against ten production APIs from Microsoft Graph to Petstore ensures real-world reliability across 19,000+ operations and 10,000+ schemas.
The modular architecture allows teams to adopt individual packages as needed while benefiting from seamless integration when using multiple components together. Whether parsing a simple specification, querying API structure with the walk command, validating runtime HTTP traffic, integrating with AI tools via MCP, or generating complete client/server implementations with security, oastools provides the foundation for robust API development in Go.
-
OpenAPI Specification v2.0. OpenAPI Initiative. https://spec.openapis.org/oas/v2.0.html
-
OpenAPI Specification v3.0.0. OpenAPI Initiative. https://spec.openapis.org/oas/v3.0.0.html
-
OpenAPI Specification v3.0.3. OpenAPI Initiative. https://spec.openapis.org/oas/v3.0.3.html
-
OpenAPI Specification v3.0.4. OpenAPI Initiative. https://spec.openapis.org/oas/v3.0.4.html
-
OpenAPI Specification v3.1.0. OpenAPI Initiative. https://spec.openapis.org/oas/v3.1.0.html
-
OpenAPI Specification v3.1.2. OpenAPI Initiative. https://spec.openapis.org/oas/v3.1.2.html
-
OpenAPI Specification v3.2.0. OpenAPI Initiative. https://spec.openapis.org/oas/v3.2.0.html
-
OpenAPI Overlay Specification v1.0.0. OpenAPI Initiative. https://spec.openapis.org/overlay/v1.0.0.html
- JSON Schema: A Media Type for Describing JSON Documents (Draft 2020-12). https://json-schema.org/draft/2020-12/json-schema-core.html
-
RFC 9535: JSONPath: Query Expressions for JSON. IETF. https://datatracker.ietf.org/doc/html/rfc9535
-
RFC 7636: Proof Key for Code Exchange (PKCE). IETF. https://datatracker.ietf.org/doc/html/rfc7636
-
RFC 6749: The OAuth 2.0 Authorization Framework. IETF. https://datatracker.ietf.org/doc/html/rfc6749
-
RFC 3986: Uniform Resource Identifier (URI): Generic Syntax. IETF. https://datatracker.ietf.org/doc/html/rfc3986
-
RFC 6570: URI Template. IETF. https://datatracker.ietf.org/doc/html/rfc6570
-
The Go Programming Language Specification. https://go.dev/ref/spec
-
Go 1.25 Release Notes. https://go.dev/doc/go1.25
-
oastools GitHub Repository. https://github.com/erraggy/oastools
-
oastools API Documentation. https://pkg.go.dev/github.com/erraggy/oastools
-
oastools GitHub Pages. https://erraggy.github.io/oastools/
| Package | pkg.go.dev | Deep Dive |
|---|---|---|
| parser | pkg.go.dev | Deep Dive |
| validator | pkg.go.dev | Deep Dive |
| fixer | pkg.go.dev | Deep Dive |
| converter | pkg.go.dev | Deep Dive |
| joiner | pkg.go.dev | Deep Dive |
| overlay | pkg.go.dev | Deep Dive |
| differ | pkg.go.dev | Deep Dive |
| generator | pkg.go.dev | Deep Dive |
| builder | pkg.go.dev | Deep Dive |
| httpvalidator | pkg.go.dev | Deep Dive |
| walker | pkg.go.dev | Deep Dive |
| oaserrors | pkg.go.dev | — |
-
Model Context Protocol Specification. https://modelcontextprotocol.io/
-
Go MCP SDK. https://github.com/modelcontextprotocol/go-sdk
For the latest features, updates, and documentation, visit the GitHub repository or the documentation site.