Parser Package Deep Dive
The parser package provides parsing for OpenAPI Specification documents, supporting OAS 2.0 through OAS 3.2.0 in YAML and JSON formats.
Table of Contents
- Overview
- Key Concepts
- OAS 3.2.0 Features
- JSON Schema 2020-12 Support
- API Styles
- Practical Examples
- Configuration Reference
- Document Type Helpers
- Version-Agnostic Access (DocumentAccessor)
- Best Practices
Overview
The parser can load specifications from local files or remote URLs, resolve external references ($ref), validate structure, and preserve unknown fields for forward compatibility. It automatically detects the file format (JSON/YAML) and OAS version.
Key capabilities:
- Parse files, URLs, readers, or byte slices
- Resolve local and external $ref references
- Detect and handle circular references safely
- Enforce configurable resource limits
- Preserve source format for downstream tools
Key Concepts
Format Detection
The parser automatically detects format from:
1. File extension (.json, .yaml, .yml)
2. Content inspection (JSON starts with { or [)
3. Defaults to YAML if unknown
Reference Resolution
External $ref values are resolved when ResolveRefs is enabled:
| Reference Type | Example | Security |
|---|---|---|
| Local | #/components/schemas/User |
Always allowed |
| File | ./common.yaml#/schemas/Error |
Path traversal protected |
| HTTP/HTTPS | https://example.com/schemas.yaml |
Opt-in via WithResolveHTTPRefs |
Circular Reference Handling
When circular references are detected:
- The $ref node is left unresolved (preserves the "$ref" key)
- A warning is added to result.Warnings
- The document remains valid for most operations
Detection triggers:
- A $ref points to an ancestor in the current resolution path
- Resolution depth exceeds MaxRefDepth (default: 100)
Resource Limits
| 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 |
OAS 3.2.0 Features
OAS 3.2.0 introduces several new capabilities that the parser fully supports:
Document Identity ($self)
The $self field provides a canonical URL for the document:
result, _ := parser.ParseWithOptions(parser.WithFilePath("api.yaml"))
doc, _ := result.OAS3Document()
if doc.Self != "" {
fmt.Printf("Document identity: %s\n", doc.Self)
}
Additional HTTP Methods (additionalOperations)
Custom HTTP methods beyond the standard set can be defined via additionalOperations:
pathItem := doc.Paths["/resource"]
for method, op := range pathItem.AdditionalOperations {
fmt.Printf("Custom method %s: %s\n", method, op.OperationID)
}
// Use GetOperations to get all operations including custom methods
allOps := parser.GetOperations(pathItem, parser.OASVersion320)
Reusable Media Types (components/mediaTypes)
Media type definitions can be defined once and referenced:
if doc.Components != nil && doc.Components.MediaTypes != nil {
for name, mediaType := range doc.Components.MediaTypes {
fmt.Printf("Media type %s: %v\n", name, mediaType.Schema)
}
}
QUERY Method
OAS 3.2.0 adds native support for the QUERY HTTP method:
JSON Schema 2020-12 Support
The parser supports all JSON Schema Draft 2020-12 keywords used in OAS 3.1+:
Content Keywords
For schemas representing encoded content:
| Keyword | Type | Description |
|---|---|---|
contentEncoding |
string |
Encoding (e.g., "base64", "base32") |
contentMediaType |
string |
Media type of decoded content |
contentSchema |
*Schema |
Schema for decoded content |
schema := doc.Components.Schemas["EncodedData"]
if schema.ContentEncoding != "" {
fmt.Printf("Encoding: %s, Media type: %s\n",
schema.ContentEncoding, schema.ContentMediaType)
}
Unevaluated Keywords
For strict validation of object and array schemas:
| Keyword | Type | Description |
|---|---|---|
unevaluatedProperties |
any |
*Schema, bool, or map[string]any for uncovered properties |
unevaluatedItems |
any |
*Schema, bool, or map[string]any for uncovered array items |
schema := doc.Components.Schemas["StrictObject"]
switch v := schema.UnevaluatedProperties.(type) {
case *parser.Schema:
// Typed schema - most common after parsing
fmt.Printf("Unevaluated properties must match: %s\n", v.Ref)
case bool:
// Boolean value - false disallows, true allows any
fmt.Printf("Unevaluated properties allowed: %v\n", v)
case map[string]any:
// Raw map - when schema wasn't typed during parsing
if ref, ok := v["$ref"].(string); ok {
fmt.Printf("Raw ref to: %s\n", ref)
}
default:
// nil or unexpected type
fmt.Println("No unevaluatedProperties constraint")
}
Array Index References
JSON Pointer references now support array indices per RFC 6901:
The resolver handles:
- Valid indices: 0, 1, 2, etc.
- Out-of-bounds errors with descriptive messages
- Non-numeric index errors
API Styles
See also: Basic example, Functional options example, Reusable parser example on pkg.go.dev
Functional Options (Recommended)
result, err := parser.ParseWithOptions(
parser.WithFilePath("openapi.yaml"),
parser.WithValidateStructure(true),
parser.WithResolveRefs(true),
)
if err != nil {
log.Fatal(err)
}
Struct-Based (Reusable)
p := parser.New()
p.ResolveRefs = false
p.ValidateStructure = true
result1, _ := p.Parse("api1.yaml")
result2, _ := p.Parse("api2.yaml")
Alternative Input Sources
// From URL
result, _ := parser.ParseWithOptions(
parser.WithFilePath("https://example.com/api/openapi.yaml"),
)
// From reader
result, _ := p.ParseReader(reader, "config.yaml")
// From bytes
result, _ := p.ParseBytes(data, "inline.yaml")
Practical Examples
Basic File Parsing
result, err := parser.ParseWithOptions(
parser.WithFilePath("openapi.yaml"),
)
if err != nil {
log.Fatal(err)
}
if len(result.Errors) > 0 {
fmt.Printf("Parse errors: %d\n", len(result.Errors))
}
fmt.Printf("Parsed %s v%s\n", result.Version, result.OASVersion)
HTTP Reference Resolution
See also: HTTP refs example, Parse from URL example on pkg.go.dev
result, err := parser.ParseWithOptions(
parser.WithFilePath("openapi.yaml"),
parser.WithResolveHTTPRefs(true), // Enable HTTP refs
parser.WithInsecureSkipVerify(true), // For self-signed certs
)
Custom Resource Limits
result, err := parser.ParseWithOptions(
parser.WithFilePath("large-api.yaml"),
parser.WithMaxRefDepth(50),
parser.WithMaxCachedDocuments(200),
parser.WithMaxFileSize(20*1024*1024), // 20MB
)
Safe Document Mutation with DeepCopy
See also: DeepCopy example on pkg.go.dev
result, _ := parser.ParseWithOptions(parser.WithFilePath("api.yaml"))
// Deep copy before mutation
copy := result.OAS3Document.DeepCopy()
copy.Info.Title = "Modified API"
// Original unchanged
fmt.Println(result.OAS3Document.Info.Title) // Original title
Configuration Reference
Functional Options
| Option | Description |
|---|---|
WithFilePath(path) |
File path or URL to parse |
WithResolveRefs(bool) |
Enable $ref resolution (default: true) |
WithResolveHTTPRefs(bool) |
Enable HTTP/HTTPS ref resolution (default: false) |
WithValidateStructure(bool) |
Validate document structure during parsing |
WithInsecureSkipVerify(bool) |
Skip TLS verification for HTTPS refs |
WithMaxRefDepth(n) |
Max nested ref depth (default: 100) |
WithMaxCachedDocuments(n) |
Max cached external docs (default: 100) |
WithMaxFileSize(n) |
Max file size in bytes (default: 10MB) |
ParseResult Fields
| Field | Type | Description |
|---|---|---|
Document |
any |
Parsed document (OAS2Document or OAS3Document) |
Version |
string |
Raw version string from document |
OASVersion |
OASVersion |
Parsed version constant |
SourceFormat |
SourceFormat |
Detected format (JSON or YAML) |
SourcePath |
string |
Original file path |
Errors |
[]string |
Parse errors |
Warnings |
[]string |
Non-fatal warnings |
Document Type Helpers
See also: Document type helpers example on pkg.go.dev
ParseResult provides convenient methods for version checking and type assertion:
result, _ := parser.ParseWithOptions(parser.WithFilePath("api.yaml"))
// Version checking
if result.IsOAS2() {
fmt.Println("This is a Swagger 2.0 document")
}
if result.IsOAS3() {
fmt.Println("This is an OAS 3.x document")
}
// Safe type assertion
if doc, ok := result.OAS3Document(); ok {
fmt.Printf("API: %s v%s\n", doc.Info.Title, doc.Info.Version)
}
if doc, ok := result.OAS2Document(); ok {
fmt.Printf("Swagger: %s v%s\n", doc.Info.Title, doc.Info.Version)
}
Version-Agnostic Access (DocumentAccessor)
See also: DocumentAccessor example on pkg.go.dev
For code that needs to work uniformly across both OAS 2.0 and 3.x documents without type switches, use the DocumentAccessor interface:
result, _ := parser.ParseWithOptions(parser.WithFilePath("api.yaml"))
if accessor := result.AsAccessor(); accessor != nil {
// These methods work identically for both versions
for path := range accessor.GetPaths() {
fmt.Println("Path:", path)
}
// GetSchemas() abstracts the difference:
// - OAS 2.0: returns doc.Definitions
// - OAS 3.x: returns doc.Components.Schemas
for name := range accessor.GetSchemas() {
fmt.Println("Schema:", name)
}
// Get the $ref prefix for schema references
fmt.Println("Prefix:", accessor.SchemaRefPrefix())
}
DocumentAccessor 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 |
SchemaRefPrefix() |
#/definitions/ |
#/components/schemas/ |
Best Practices
- Parse once, use many - Cache ParseResult for operations like validate, convert, diff
- Use pre-parsed methods -
ValidateParsed(),ConvertParsed(), etc. are 9-150x faster - Check warnings for circular refs - They indicate unresolved references
- Enable HTTP refs carefully - Only for trusted sources; use
WithInsecureSkipVerifysparingly - Use DeepCopy for mutations - Never modify the original parsed document
Learn More
For additional examples and complete API documentation:
- 📦 API Reference on pkg.go.dev - Complete API documentation with all examples
- 🔧 Functional options example - Configure parsing with options
- 🌐 HTTP refs example - Resolve external HTTP references
- 📋 DeepCopy example - Safe document mutation
- 🔍 Type helpers example - Version checking and type assertions
- 🔀 DocumentAccessor example - Version-agnostic document access