Documentation
¶
Overview ¶
Package walker provides a document traversal API for OpenAPI specifications.
The walker enables single-pass traversal of OAS 2.0, 3.0.x, 3.1.x, and 3.2.0 documents, allowing handlers to receive and optionally mutate nodes. This is useful for analysis, transformation, and validation tasks that need to inspect or modify multiple parts of a specification in a consistent way.
Quick Start ¶
Walk a document and collect all operation IDs:
result, _ := parser.ParseWithOptions(parser.WithFilePath("api.yaml"))
var operationIDs []string
err := walker.Walk(result,
walker.WithOperationHandler(func(wc *walker.WalkContext, op *parser.Operation) walker.Action {
operationIDs = append(operationIDs, op.OperationID)
return walker.Continue
}),
)
Flow Control ¶
Handlers return an Action to control traversal:
- Continue: continue traversing children and siblings normally
- SkipChildren: skip all children of the current node, continue with siblings
- Stop: stop the entire walk immediately
Example using SkipChildren to avoid internal paths:
walker.Walk(result,
walker.WithPathHandler(func(wc *walker.WalkContext, pathItem *parser.PathItem) walker.Action {
if strings.HasPrefix(wc.PathTemplate, "/internal") {
return walker.SkipChildren
}
return walker.Continue
}),
)
Handler Types ¶
The walker provides typed handlers for all major OAS node types:
- DocumentHandler: root OAS2Document or OAS3Document
- InfoHandler: API metadata
- ServerHandler: server definitions (OAS 3.x only)
- TagHandler: tag definitions
- PathHandler: path entries with template string
- PathItemHandler: path item containing operations
- OperationHandler: individual HTTP operations
- ParameterHandler: parameters at path or operation level
- RequestBodyHandler: request body definitions (OAS 3.x only)
- ResponseHandler: response definitions
- SchemaHandler: all schemas including nested schemas
- SecuritySchemeHandler: security scheme definitions
- HeaderHandler: header definitions
- MediaTypeHandler: media type definitions (OAS 3.x only)
- LinkHandler: link definitions (OAS 3.x only)
- CallbackHandler: callback definitions (OAS 3.x only)
- ExampleHandler: example definitions
- ExternalDocsHandler: external documentation references
Post-Visit Handlers ¶
Post-visit handlers are called after a node's children have been processed, enabling bottom-up processing patterns like aggregation:
- WithSchemaPostHandler: Called after schema children processed
- WithOperationPostHandler: Called after operation children processed
- WithPathItemPostHandler: Called after path item children processed
- WithResponsePostHandler: Called after response children processed
- WithRequestBodyPostHandler: Called after request body children processed
- WithCallbackPostHandler: Called after callback children processed
Post handlers are not called if the pre-visit handler returned SkipChildren or Stop.
Parent Tracking ¶
Enable parent tracking to access ancestor nodes during traversal:
walker.Walk(result,
walker.WithParentTracking(),
walker.WithSchemaHandler(func(wc *walker.WalkContext, s *parser.Schema) walker.Action {
if op, ok := wc.ParentOperation(); ok {
// Access containing operation
}
return walker.Continue
}),
)
Helper methods: WalkContext.ParentSchema, WalkContext.ParentOperation, WalkContext.ParentPathItem, WalkContext.ParentResponse, WalkContext.ParentRequestBody, WalkContext.Ancestors, WalkContext.Depth.
Reference Tracking ¶
Use WithRefHandler to receive callbacks when $ref values are encountered:
walker.Walk(result,
walker.WithRefHandler(func(wc *walker.WalkContext, ref *walker.RefInfo) walker.Action {
fmt.Printf("Found ref: %s at %s\n", ref.Ref, ref.SourcePath)
return walker.Continue
}),
)
Mutation Support ¶
Handlers receive pointers to the actual nodes, so mutations are applied directly:
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
}),
)
WalkContext ¶
Every handler receives a WalkContext as its first parameter, providing contextual information about the current node:
- JSONPath: Full JSON path to the node (always populated)
- PathTemplate: URL path template when in $.paths scope
- Method: HTTP method when in operation scope (e.g., "get", "post")
- StatusCode: Status code when in response scope (e.g., "200", "default")
- Name: Map key for named items (headers, schemas, etc.)
- IsComponent: True when in components/definitions section
Example JSON paths:
$.info // Info object
$.paths['/pets/{petId}'] // Path entry
$.paths['/pets'].get // Operation
$.components.schemas['Pet'] // Schema
Use helper methods like WalkContext.InOperationScope and WalkContext.InResponseScope for scope checks.
Context Propagation ¶
Pass a context.Context for cancellation and timeout support:
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
walker.Walk(result,
walker.WithContext(ctx),
walker.WithSchemaHandler(func(wc *walker.WalkContext, schema *parser.Schema) walker.Action {
if wc.Context().Err() != nil {
return walker.Stop
}
return walker.Continue
}),
)
Performance Considerations ¶
The walker uses the Parse-Once pattern. Always prefer passing a pre-parsed parser.ParseResult rather than re-parsing:
// Good: parse once, walk multiple times
result, _ := parser.ParseWithOptions(parser.WithFilePath("api.yaml"))
walker.Walk(result, handlers1...)
walker.Walk(result, handlers2...)
Schema Cycle Detection ¶
The walker automatically detects circular schema references and avoids infinite loops. Use WithMaxSchemaDepth to limit recursion depth for deeply nested schemas (default: 100).
Related Packages ¶
- github.com/erraggy/oastools/parser - Parse specifications before walking
- github.com/erraggy/oastools/validator - Validate OAS documents
- github.com/erraggy/oastools/fixer - Automatically fix common issues
- github.com/erraggy/oastools/converter - Convert between OAS versions
Index ¶
- func Walk(result *parser.ParseResult, opts ...Option) error
- func WalkWithOptions(opts ...Option) error
- type Action
- type CallbackHandler
- type CallbackPostHandler
- type DocumentHandler
- type ExampleHandler
- type ExternalDocsHandler
- type HeaderHandler
- type InfoHandler
- type LinkHandler
- type MediaTypeHandler
- type OAS2DocumentHandler
- type OAS3DocumentHandler
- type OperationCollector
- type OperationHandler
- type OperationInfo
- type OperationPostHandler
- type Option
- func WithCallbackHandler(fn CallbackHandler) Option
- func WithCallbackPostHandler(fn CallbackPostHandler) Option
- func WithContext(ctx context.Context) Option
- func WithDocumentHandler(fn DocumentHandler) Option
- func WithExampleHandler(fn ExampleHandler) Option
- func WithExternalDocsHandler(fn ExternalDocsHandler) Option
- func WithFilePath(path string) Option
- func WithHeaderHandler(fn HeaderHandler) Option
- func WithInfoHandler(fn InfoHandler) Option
- func WithLinkHandler(fn LinkHandler) Option
- func WithMaxDepth(depth int) Optiondeprecated
- func WithMaxSchemaDepth(depth int) Option
- func WithMediaTypeHandler(fn MediaTypeHandler) Option
- func WithOAS2DocumentHandler(fn OAS2DocumentHandler) Option
- func WithOAS3DocumentHandler(fn OAS3DocumentHandler) Option
- func WithOperationHandler(fn OperationHandler) Option
- func WithOperationPostHandler(fn OperationPostHandler) Option
- func WithParameterHandler(fn ParameterHandler) Option
- func WithParentTracking() Option
- func WithParsed(result *parser.ParseResult) Option
- func WithPathHandler(fn PathHandler) Option
- func WithPathItemHandler(fn PathItemHandler) Option
- func WithPathItemPostHandler(fn PathItemPostHandler) Option
- func WithRefHandler(fn RefHandler) Option
- func WithRefTracking() Option
- func WithRequestBodyHandler(fn RequestBodyHandler) Option
- func WithRequestBodyPostHandler(fn RequestBodyPostHandler) Option
- func WithResponseHandler(fn ResponseHandler) Option
- func WithResponsePostHandler(fn ResponsePostHandler) Option
- func WithSchemaHandler(fn SchemaHandler) Option
- func WithSchemaPostHandler(fn SchemaPostHandler) Option
- func WithSchemaSkippedHandler(fn SchemaSkippedHandler) Option
- func WithSecuritySchemeHandler(fn SecuritySchemeHandler) Option
- func WithServerHandler(fn ServerHandler) Option
- func WithTagHandler(fn TagHandler) Option
- type ParameterHandler
- type ParentInfo
- type PathHandler
- type PathItemHandler
- type PathItemPostHandler
- type RefHandler
- type RefInfo
- type RefNodeType
- type RequestBodyHandler
- type RequestBodyPostHandler
- type ResponseHandler
- type ResponsePostHandler
- type SchemaCollector
- type SchemaHandler
- type SchemaInfo
- type SchemaPostHandler
- type SchemaSkippedHandler
- type SecuritySchemeHandler
- type ServerHandler
- type TagHandler
- type WalkContext
- func (wc *WalkContext) Ancestors() []*ParentInfo
- func (wc *WalkContext) Context() context.Context
- func (wc *WalkContext) Depth() int
- func (wc *WalkContext) InOperationScope() bool
- func (wc *WalkContext) InPathsScope() bool
- func (wc *WalkContext) InResponseScope() bool
- func (wc *WalkContext) ParentOperation() (*parser.Operation, bool)
- func (wc *WalkContext) ParentPathItem() (*parser.PathItem, bool)
- func (wc *WalkContext) ParentRequestBody() (*parser.RequestBody, bool)
- func (wc *WalkContext) ParentResponse() (*parser.Response, bool)
- func (wc *WalkContext) ParentSchema() (*parser.Schema, bool)
- func (wc *WalkContext) WithContext(ctx context.Context) *WalkContext
- type Walker
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func Walk ¶
func Walk(result *parser.ParseResult, opts ...Option) error
Walk traverses the parsed document and calls registered handlers for each node.
Example ¶
package main
import (
"fmt"
"github.com/erraggy/oastools/parser"
"github.com/erraggy/oastools/walker"
)
func main() {
doc := &parser.OAS3Document{
OpenAPI: "3.0.3",
Info: &parser.Info{
Title: "Pet Store API",
Version: "1.0.0",
},
Paths: parser.Paths{
"/pets": &parser.PathItem{
Get: &parser.Operation{
OperationID: "listPets",
Summary: "List all pets",
},
Post: &parser.Operation{
OperationID: "createPet",
Summary: "Create a pet",
},
},
},
}
result := &parser.ParseResult{
Document: doc,
OASVersion: parser.OASVersion303,
}
var operationIDs []string
_ = walker.Walk(result,
walker.WithOperationHandler(func(wc *walker.WalkContext, op *parser.Operation) walker.Action {
operationIDs = append(operationIDs, op.OperationID)
return walker.Continue
}),
)
for _, id := range operationIDs {
fmt.Println(id)
}
}
Output: listPets createPet
Example (CollectSchemas) ¶
package main
import (
"fmt"
"github.com/erraggy/oastools/parser"
"github.com/erraggy/oastools/walker"
)
func main() {
doc := &parser.OAS3Document{
OpenAPI: "3.0.3",
Info: &parser.Info{Title: "Test", Version: "1.0.0"},
Components: &parser.Components{
Schemas: map[string]*parser.Schema{
"Pet": {
Type: "object",
Properties: map[string]*parser.Schema{
"name": {Type: "string"},
"age": {Type: "integer"},
},
},
},
},
}
result := &parser.ParseResult{
Document: doc,
OASVersion: parser.OASVersion303,
}
typeCounts := make(map[string]int)
_ = walker.Walk(result,
walker.WithSchemaHandler(func(wc *walker.WalkContext, schema *parser.Schema) walker.Action {
if schemaType, ok := schema.Type.(string); ok && schemaType != "" {
typeCounts[schemaType]++
}
return walker.Continue
}),
)
fmt.Println("object:", typeCounts["object"])
fmt.Println("string:", typeCounts["string"])
fmt.Println("integer:", typeCounts["integer"])
}
Output: object: 1 string: 1 integer: 1
Example (DocumentTypeSwitch) ¶
package main
import (
"fmt"
"github.com/erraggy/oastools/parser"
"github.com/erraggy/oastools/walker"
)
func main() {
oas3Doc := &parser.OAS3Document{
OpenAPI: "3.0.3",
Info: &parser.Info{Title: "OAS 3.x API", Version: "1.0.0"},
}
result := &parser.ParseResult{
Document: oas3Doc,
OASVersion: parser.OASVersion303,
}
_ = walker.Walk(result,
walker.WithDocumentHandler(func(wc *walker.WalkContext, doc any) walker.Action {
switch d := doc.(type) {
case *parser.OAS2Document:
fmt.Println("OAS 2.0:", d.Info.Title)
case *parser.OAS3Document:
fmt.Println("OAS 3.x:", d.Info.Title)
}
return walker.Continue
}),
)
}
Output: OAS 3.x: OAS 3.x API
Example (JsonPaths) ¶
package main
import (
"fmt"
"github.com/erraggy/oastools/parser"
"github.com/erraggy/oastools/walker"
)
func main() {
doc := &parser.OAS3Document{
OpenAPI: "3.0.3",
Info: &parser.Info{Title: "Test", Version: "1.0.0"},
Paths: parser.Paths{
"/pets": &parser.PathItem{
Get: &parser.Operation{OperationID: "getPets"},
},
},
}
result := &parser.ParseResult{
Document: doc,
OASVersion: parser.OASVersion303,
}
_ = walker.Walk(result,
walker.WithOperationHandler(func(wc *walker.WalkContext, op *parser.Operation) walker.Action {
fmt.Printf("Operation %s at: %s\n", op.OperationID, wc.JSONPath)
return walker.Continue
}),
)
}
Output: Operation getPets at: $.paths['/pets'].get
Example (Mutation) ¶
package main
import (
"fmt"
"github.com/erraggy/oastools/parser"
"github.com/erraggy/oastools/walker"
)
func main() {
doc := &parser.OAS3Document{
OpenAPI: "3.0.3",
Info: &parser.Info{Title: "Test", Version: "1.0.0"},
Components: &parser.Components{
Schemas: map[string]*parser.Schema{
"Pet": {Type: "object"},
},
},
}
result := &parser.ParseResult{
Document: doc,
OASVersion: parser.OASVersion303,
}
_ = 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-visited"] = true
return walker.Continue
}),
)
fmt.Printf("x-visited: %v\n", doc.Components.Schemas["Pet"].Extra["x-visited"])
}
Output: x-visited: true
Example (SkipChildren) ¶
package main
import (
"fmt"
"github.com/erraggy/oastools/parser"
"github.com/erraggy/oastools/walker"
)
func main() {
doc := &parser.OAS3Document{
OpenAPI: "3.0.3",
Info: &parser.Info{Title: "Test", Version: "1.0.0"},
Paths: parser.Paths{
"/internal": &parser.PathItem{
Get: &parser.Operation{OperationID: "internalOp"},
},
"/public": &parser.PathItem{
Get: &parser.Operation{OperationID: "publicOp"},
},
},
}
result := &parser.ParseResult{
Document: doc,
OASVersion: parser.OASVersion303,
}
var visitedOps []string
_ = walker.Walk(result,
walker.WithPathHandler(func(wc *walker.WalkContext, pathItem *parser.PathItem) walker.Action {
if wc.PathTemplate == "/internal" {
return walker.SkipChildren
}
return walker.Continue
}),
walker.WithOperationHandler(func(wc *walker.WalkContext, op *parser.Operation) walker.Action {
visitedOps = append(visitedOps, op.OperationID)
return walker.Continue
}),
)
fmt.Println("Visited:", visitedOps)
}
Output: Visited: [publicOp]
Example (Stop) ¶
package main
import (
"fmt"
"github.com/erraggy/oastools/parser"
"github.com/erraggy/oastools/walker"
)
func main() {
doc := &parser.OAS3Document{
OpenAPI: "3.0.3",
Info: &parser.Info{Title: "Test", Version: "1.0.0"},
Paths: parser.Paths{
"/a": &parser.PathItem{Get: &parser.Operation{OperationID: "opA"}},
"/b": &parser.PathItem{Get: &parser.Operation{OperationID: "opB"}},
"/c": &parser.PathItem{Get: &parser.Operation{OperationID: "opC"}},
},
}
result := &parser.ParseResult{
Document: doc,
OASVersion: parser.OASVersion303,
}
var firstOp string
_ = walker.Walk(result,
walker.WithOperationHandler(func(wc *walker.WalkContext, op *parser.Operation) walker.Action {
firstOp = op.OperationID
return walker.Stop
}),
)
fmt.Println("First operation:", firstOp)
}
Output: First operation: opA
func WalkWithOptions ¶
WalkWithOptions walks a document using functional options for input, handlers, and configuration. All options use the unified Option type - no adapter is needed.
Example:
walker.WalkWithOptions(
walker.WithFilePath("openapi.yaml"),
walker.WithSchemaHandler(func(wc *walker.WalkContext, s *parser.Schema) walker.Action {
fmt.Println(wc.JSONPath)
return walker.Continue
}),
)
Example ¶
package main
import (
"fmt"
"github.com/erraggy/oastools/parser"
"github.com/erraggy/oastools/walker"
)
func main() {
doc := &parser.OAS3Document{
OpenAPI: "3.0.3",
Info: &parser.Info{Title: "Test", Version: "1.0.0"},
Components: &parser.Components{
Schemas: map[string]*parser.Schema{
"Pet": {Type: "object"},
},
},
}
result := &parser.ParseResult{
Document: doc,
OASVersion: parser.OASVersion303,
}
var schemaCount int
_ = walker.WalkWithOptions(
walker.WithParsed(result),
walker.WithSchemaHandler(func(wc *walker.WalkContext, schema *parser.Schema) walker.Action {
schemaCount++
return walker.Continue
}),
)
fmt.Println("Schema count:", schemaCount)
}
Output: Schema count: 1
Types ¶
type Action ¶
type Action int
Action controls the walker's behavior after visiting a node.
type CallbackHandler ¶
type CallbackHandler func(wc *WalkContext, callback parser.Callback) Action
CallbackHandler is called for each Callback (OAS 3.x only). The callback name is available in wc.Name. The JSON path is in wc.JSONPath.
type CallbackPostHandler ¶ added in v1.39.0
type CallbackPostHandler func(wc *WalkContext, callback parser.Callback)
CallbackPostHandler is called after a callback's children have been processed.
type DocumentHandler ¶
type DocumentHandler func(wc *WalkContext, doc any) Action
DocumentHandler is called for the root document (OAS2Document or OAS3Document). The JSON path is available in wc.JSONPath.
type ExampleHandler ¶
type ExampleHandler func(wc *WalkContext, example *parser.Example) Action
ExampleHandler is called for each Example. The example name is available in wc.Name. The JSON path is in wc.JSONPath.
type ExternalDocsHandler ¶
type ExternalDocsHandler func(wc *WalkContext, extDocs *parser.ExternalDocs) Action
ExternalDocsHandler is called for each ExternalDocs. The JSON path is available in wc.JSONPath.
type HeaderHandler ¶
type HeaderHandler func(wc *WalkContext, header *parser.Header) Action
HeaderHandler is called for each Header. The header name is available in wc.Name. The JSON path is in wc.JSONPath.
type InfoHandler ¶
type InfoHandler func(wc *WalkContext, info *parser.Info) Action
InfoHandler is called for the Info object. The JSON path is available in wc.JSONPath.
type LinkHandler ¶
type LinkHandler func(wc *WalkContext, link *parser.Link) Action
LinkHandler is called for each Link (OAS 3.x only). The link name is available in wc.Name. The JSON path is in wc.JSONPath.
type MediaTypeHandler ¶
type MediaTypeHandler func(wc *WalkContext, mt *parser.MediaType) Action
MediaTypeHandler is called for each MediaType (OAS 3.x only). The media type name is available in wc.Name. The JSON path is in wc.JSONPath.
type OAS2DocumentHandler ¶
type OAS2DocumentHandler func(wc *WalkContext, doc *parser.OAS2Document) Action
OAS2DocumentHandler is called for OAS 2.0 (Swagger) documents. The JSON path is available in wc.JSONPath.
type OAS3DocumentHandler ¶
type OAS3DocumentHandler func(wc *WalkContext, doc *parser.OAS3Document) Action
OAS3DocumentHandler is called for OAS 3.x documents. The JSON path is available in wc.JSONPath.
type OperationCollector ¶ added in v1.39.0
type OperationCollector struct {
// All contains all operations in traversal order.
All []*OperationInfo
// ByPath groups operations by path template.
ByPath map[string][]*OperationInfo
// ByMethod groups operations by HTTP method.
ByMethod map[string][]*OperationInfo
// ByTag groups operations by tag name.
// Operations with multiple tags appear in multiple groups.
// Operations without tags are not included in this map.
ByTag map[string][]*OperationInfo
}
OperationCollector holds operations collected during a walk.
func CollectOperations ¶ added in v1.39.0
func CollectOperations(result *parser.ParseResult) (*OperationCollector, error)
CollectOperations walks the document and collects all operations. It returns an OperationCollector containing all operations organized by various criteria.
Example ¶
package main
import (
"fmt"
"github.com/erraggy/oastools/parser"
"github.com/erraggy/oastools/walker"
)
func main() {
doc := &parser.OAS3Document{
OpenAPI: "3.0.3",
Info: &parser.Info{Title: "Pet Store", Version: "1.0.0"},
Paths: parser.Paths{
"/pets": &parser.PathItem{
Get: &parser.Operation{
OperationID: "listPets",
Tags: []string{"pets"},
},
Post: &parser.Operation{
OperationID: "createPet",
Tags: []string{"pets"},
},
},
"/pets/{petId}": &parser.PathItem{
Get: &parser.Operation{
OperationID: "getPet",
Tags: []string{"pets"},
},
},
},
}
result := &parser.ParseResult{
Document: doc,
OASVersion: parser.OASVersion303,
}
// Collect all operations
ops, _ := walker.CollectOperations(result)
// Print operation counts
fmt.Printf("Total operations: %d\n", len(ops.All))
// Group by tag
for tag, tagOps := range ops.ByTag {
fmt.Printf("Tag '%s' has %d operations\n", tag, len(tagOps))
}
}
Output: Total operations: 3 Tag 'pets' has 3 operations
type OperationHandler ¶
type OperationHandler func(wc *WalkContext, op *parser.Operation) Action
OperationHandler is called for each Operation. The HTTP method is available in wc.Method. The JSON path is in wc.JSONPath.
type OperationInfo ¶ added in v1.39.0
type OperationInfo struct {
// Operation is the collected operation.
Operation *parser.Operation
// PathTemplate is the URL path template (e.g., "/pets/{petId}").
PathTemplate string
// Method is the HTTP method (e.g., "get", "post").
Method string
// JSONPath is the full JSON path to the operation.
JSONPath string
}
OperationInfo contains information about a collected operation.
type OperationPostHandler ¶ added in v1.39.0
type OperationPostHandler func(wc *WalkContext, op *parser.Operation)
OperationPostHandler is called after an operation's children have been processed.
type Option ¶
type Option func(*Walker)
Option configures the Walker.
func WithCallbackHandler ¶
func WithCallbackHandler(fn CallbackHandler) Option
WithCallbackHandler sets the handler for Callback objects (OAS 3.x only).
func WithCallbackPostHandler ¶ added in v1.39.0
func WithCallbackPostHandler(fn CallbackPostHandler) Option
WithCallbackPostHandler sets a handler called after a callback's children are processed. Not called if the pre-visit handler returns SkipChildren or Stop.
func WithContext ¶ added in v1.38.0
WithContext sets the context for cancellation and deadline propagation. The context is available to handlers via wc.Context().
func WithDocumentHandler ¶
func WithDocumentHandler(fn DocumentHandler) Option
WithDocumentHandler sets the handler for the root document.
func WithExampleHandler ¶
func WithExampleHandler(fn ExampleHandler) Option
WithExampleHandler sets the handler for Example objects.
func WithExternalDocsHandler ¶
func WithExternalDocsHandler(fn ExternalDocsHandler) Option
WithExternalDocsHandler sets the handler for ExternalDocs objects.
func WithFilePath ¶
WithFilePath specifies a file path to parse and walk.
func WithHeaderHandler ¶
func WithHeaderHandler(fn HeaderHandler) Option
WithHeaderHandler sets the handler for Header objects.
func WithInfoHandler ¶
func WithInfoHandler(fn InfoHandler) Option
WithInfoHandler sets the handler for Info objects.
func WithLinkHandler ¶
func WithLinkHandler(fn LinkHandler) Option
WithLinkHandler sets the handler for Link objects (OAS 3.x only).
func WithMaxDepth
deprecated
WithMaxDepth sets the maximum schema recursion depth. The default depth is 100.
Depth must be a positive integer (>= 1). Values of 0 or negative are silently ignored and the default of 100 is kept. There is no "unlimited" depth option to prevent infinite recursion in circular schemas.
When the depth limit is reached, the walker skips the schema and calls the schema-skipped handler (if registered) with reason "depth".
Deprecated: Use WithMaxSchemaDepth instead for clarity.
func WithMaxSchemaDepth ¶
WithMaxSchemaDepth sets the maximum schema recursion depth. The default depth is 100.
Depth must be a positive integer (>= 1). Values of 0 or negative are silently ignored and the default of 100 is kept. There is no "unlimited" depth option to prevent infinite recursion in circular schemas.
When the depth limit is reached, the walker skips the schema and calls the schema-skipped handler (if registered) with reason "depth".
func WithMediaTypeHandler ¶
func WithMediaTypeHandler(fn MediaTypeHandler) Option
WithMediaTypeHandler sets the handler for MediaType objects (OAS 3.x only).
func WithOAS2DocumentHandler ¶
func WithOAS2DocumentHandler(fn OAS2DocumentHandler) Option
WithOAS2DocumentHandler sets the handler for OAS 2.0 (Swagger) documents. This handler is called before the generic DocumentHandler.
func WithOAS3DocumentHandler ¶
func WithOAS3DocumentHandler(fn OAS3DocumentHandler) Option
WithOAS3DocumentHandler sets the handler for OAS 3.x documents. This handler is called before the generic DocumentHandler.
func WithOperationHandler ¶
func WithOperationHandler(fn OperationHandler) Option
WithOperationHandler sets the handler for Operation objects.
func WithOperationPostHandler ¶ added in v1.39.0
func WithOperationPostHandler(fn OperationPostHandler) Option
WithOperationPostHandler sets a handler called after an operation's children are processed. Not called if the pre-visit handler returns SkipChildren or Stop.
func WithParameterHandler ¶
func WithParameterHandler(fn ParameterHandler) Option
WithParameterHandler sets the handler for Parameter objects.
func WithParentTracking ¶ added in v1.39.0
func WithParentTracking() Option
WithParentTracking enables tracking of parent nodes during traversal. When enabled, WalkContext.Parent provides access to ancestor nodes, and helper methods like ParentSchema(), ParentOperation(), ParentPathItem(), ParentResponse(), ParentRequestBody(), Ancestors(), and Depth() become available.
This adds some overhead (parent stack management), so only enable when needed. By default, parent tracking is disabled for optimal performance.
Example ¶
package main
import (
"fmt"
"github.com/erraggy/oastools/parser"
"github.com/erraggy/oastools/walker"
)
func main() {
doc := &parser.OAS3Document{
OpenAPI: "3.0.3",
Info: &parser.Info{Title: "Pet Store", Version: "1.0.0"},
Paths: parser.Paths{
"/pets": &parser.PathItem{
Get: &parser.Operation{
OperationID: "listPets",
Responses: &parser.Responses{
Codes: map[string]*parser.Response{
"200": {
Description: "Success",
Content: map[string]*parser.MediaType{
"application/json": {
Schema: &parser.Schema{Type: "array"},
},
},
},
},
},
},
},
},
}
result := &parser.ParseResult{
Document: doc,
OASVersion: parser.OASVersion303,
}
_ = walker.Walk(result,
walker.WithParentTracking(),
walker.WithSchemaHandler(func(wc *walker.WalkContext, schema *parser.Schema) walker.Action {
// Find which operation this schema belongs to
if op, ok := wc.ParentOperation(); ok {
fmt.Printf("Schema in operation: %s\n", op.OperationID)
}
// Check ancestor depth
fmt.Printf("Ancestor depth: %d\n", wc.Depth())
return walker.Continue
}),
)
}
Output: Schema in operation: listPets Ancestor depth: 4
func WithParsed ¶
func WithParsed(result *parser.ParseResult) Option
WithParsed specifies a pre-parsed result to walk.
func WithPathHandler ¶
func WithPathHandler(fn PathHandler) Option
WithPathHandler sets the handler for path entries.
func WithPathItemHandler ¶
func WithPathItemHandler(fn PathItemHandler) Option
WithPathItemHandler sets the handler for PathItem objects.
func WithPathItemPostHandler ¶ added in v1.39.0
func WithPathItemPostHandler(fn PathItemPostHandler) Option
WithPathItemPostHandler sets a handler called after a path item's children are processed. Not called if the pre-visit handler returns SkipChildren or Stop.
func WithRefHandler ¶ added in v1.39.0
func WithRefHandler(fn RefHandler) Option
WithRefHandler sets a handler called when a $ref is encountered. Implicitly enables ref tracking.
Example ¶
package main
import (
"fmt"
"github.com/erraggy/oastools/parser"
"github.com/erraggy/oastools/walker"
)
func main() {
doc := &parser.OAS3Document{
OpenAPI: "3.0.3",
Info: &parser.Info{Title: "Test", Version: "1.0.0"},
Components: &parser.Components{
Schemas: map[string]*parser.Schema{
"Pet": {
Type: "object",
Properties: map[string]*parser.Schema{
"owner": {Ref: "#/components/schemas/User"},
},
},
"User": {Type: "object"},
},
},
}
result := &parser.ParseResult{
Document: doc,
OASVersion: parser.OASVersion303,
}
var refs []string
_ = walker.Walk(result,
walker.WithRefHandler(func(wc *walker.WalkContext, ref *walker.RefInfo) walker.Action {
refs = append(refs, ref.Ref)
return walker.Continue
}),
)
fmt.Printf("Found %d reference(s)\n", len(refs))
for _, ref := range refs {
fmt.Println(ref)
}
}
Output: Found 1 reference(s) #/components/schemas/User
func WithRefTracking ¶ added in v1.39.0
func WithRefTracking() Option
WithRefTracking enables tracking of $ref values during traversal. When enabled, the walker tracks reference information internally. To receive the CurrentRef value, use WithRefHandler to register a callback that is invoked with the populated WalkContext.CurrentRef for each $ref.
func WithRequestBodyHandler ¶
func WithRequestBodyHandler(fn RequestBodyHandler) Option
WithRequestBodyHandler sets the handler for RequestBody objects (OAS 3.x only).
func WithRequestBodyPostHandler ¶ added in v1.39.0
func WithRequestBodyPostHandler(fn RequestBodyPostHandler) Option
WithRequestBodyPostHandler sets a handler called after a request body's children are processed. Not called if the pre-visit handler returns SkipChildren or Stop.
func WithResponseHandler ¶
func WithResponseHandler(fn ResponseHandler) Option
WithResponseHandler sets the handler for Response objects.
func WithResponsePostHandler ¶ added in v1.39.0
func WithResponsePostHandler(fn ResponsePostHandler) Option
WithResponsePostHandler sets a handler called after a response's children are processed. Not called if the pre-visit handler returns SkipChildren or Stop.
func WithSchemaHandler ¶
func WithSchemaHandler(fn SchemaHandler) Option
WithSchemaHandler sets the handler for Schema objects.
func WithSchemaPostHandler ¶ added in v1.39.0
func WithSchemaPostHandler(fn SchemaPostHandler) Option
WithSchemaPostHandler sets a handler called after a schema's children are processed. Not called if the pre-visit handler returns SkipChildren or Stop.
Example ¶
package main
import (
"fmt"
"strings"
"github.com/erraggy/oastools/parser"
"github.com/erraggy/oastools/walker"
)
func main() {
doc := &parser.OAS3Document{
OpenAPI: "3.0.3",
Info: &parser.Info{Title: "Pet Store", Version: "1.0.0"},
Components: &parser.Components{
Schemas: map[string]*parser.Schema{
"Pet": {
Type: "object",
Properties: map[string]*parser.Schema{
"name": {Type: "string"},
"age": {Type: "integer"},
"status": {Type: "string"},
},
},
"Error": {
Type: "object",
Properties: map[string]*parser.Schema{
"code": {Type: "integer"},
"message": {Type: "string"},
},
},
},
},
}
result := &parser.ParseResult{
Document: doc,
OASVersion: parser.OASVersion303,
}
// Count properties in each top-level component schema after children are processed
// Use strings.HasPrefix to identify top-level component schemas by their JSON path
_ = walker.Walk(result,
walker.WithSchemaPostHandler(func(wc *walker.WalkContext, schema *parser.Schema) {
// Only count top-level component schemas (not nested properties)
if wc.IsComponent && wc.Name != "" && !strings.Contains(wc.JSONPath, ".properties") {
fmt.Printf("%s has %d properties\n", wc.Name, len(schema.Properties))
}
}),
)
}
Output: Error has 2 properties Pet has 3 properties
func WithSchemaSkippedHandler ¶
func WithSchemaSkippedHandler(fn SchemaSkippedHandler) Option
WithSchemaSkippedHandler sets the handler called when schemas are skipped. This handler is invoked when a schema is skipped due to depth limit ("depth") or cycle detection ("cycle").
func WithSecuritySchemeHandler ¶
func WithSecuritySchemeHandler(fn SecuritySchemeHandler) Option
WithSecuritySchemeHandler sets the handler for SecurityScheme objects.
func WithServerHandler ¶
func WithServerHandler(fn ServerHandler) Option
WithServerHandler sets the handler for Server objects (OAS 3.x only).
func WithTagHandler ¶
func WithTagHandler(fn TagHandler) Option
WithTagHandler sets the handler for Tag objects.
type ParameterHandler ¶
type ParameterHandler func(wc *WalkContext, param *parser.Parameter) Action
ParameterHandler is called for each Parameter. The JSON path is available in wc.JSONPath.
type ParentInfo ¶ added in v1.39.0
type ParentInfo struct {
// Node is the parent node (*parser.Schema, *parser.Operation, etc.)
Node any
// JSONPath is the JSON path to this parent node
JSONPath string
// Parent is the grandparent, enabling ancestor chain traversal.
// nil for the root-level parent.
Parent *ParentInfo
}
ParentInfo provides information about a parent node in the traversal. This enables handlers to access ancestor nodes for context-aware processing.
type PathHandler ¶
type PathHandler func(wc *WalkContext, pathItem *parser.PathItem) Action
PathHandler is called for each path entry. The path template is available in wc.PathTemplate. The JSON path is in wc.JSONPath.
type PathItemHandler ¶
type PathItemHandler func(wc *WalkContext, pathItem *parser.PathItem) Action
PathItemHandler is called for each PathItem. The path template is available in wc.PathTemplate. The JSON path is in wc.JSONPath.
type PathItemPostHandler ¶ added in v1.39.0
type PathItemPostHandler func(wc *WalkContext, pathItem *parser.PathItem)
PathItemPostHandler is called after a path item's children have been processed.
type RefHandler ¶ added in v1.39.0
type RefHandler func(wc *WalkContext, ref *RefInfo) Action
RefHandler is called when a $ref is encountered during traversal. Return Stop to halt traversal, Continue to proceed.
type RefInfo ¶ added in v1.39.0
type RefInfo struct {
// Ref is the $ref value (e.g., "#/components/schemas/User")
Ref string
// SourcePath is the JSON path where the ref was encountered
SourcePath string
// NodeType is the type of node containing the ref.
// Use the RefNode* constants for comparison (e.g., RefNodeSchema, RefNodeParameter).
NodeType RefNodeType
}
RefInfo contains information about a $ref encountered during traversal.
type RefNodeType ¶ added in v1.39.0
type RefNodeType string
RefNodeType identifies the type of node containing a $ref.
const ( RefNodeSchema RefNodeType = "schema" RefNodeParameter RefNodeType = "parameter" RefNodeResponse RefNodeType = "response" RefNodeRequestBody RefNodeType = "requestBody" RefNodeHeader RefNodeType = "header" RefNodeLink RefNodeType = "link" RefNodeExample RefNodeType = "example" RefNodePathItem RefNodeType = "pathItem" RefNodeSecurityScheme RefNodeType = "securityScheme" )
RefNodeType constants for all supported reference types.
type RequestBodyHandler ¶
type RequestBodyHandler func(wc *WalkContext, reqBody *parser.RequestBody) Action
RequestBodyHandler is called for each RequestBody (OAS 3.x only). The JSON path is available in wc.JSONPath.
type RequestBodyPostHandler ¶ added in v1.39.0
type RequestBodyPostHandler func(wc *WalkContext, reqBody *parser.RequestBody)
RequestBodyPostHandler is called after a request body's children have been processed.
type ResponseHandler ¶
type ResponseHandler func(wc *WalkContext, resp *parser.Response) Action
ResponseHandler is called for each Response. The status code is available in wc.StatusCode. The JSON path is in wc.JSONPath.
type ResponsePostHandler ¶ added in v1.39.0
type ResponsePostHandler func(wc *WalkContext, resp *parser.Response)
ResponsePostHandler is called after a response's children have been processed.
type SchemaCollector ¶ added in v1.39.0
type SchemaCollector struct {
// All contains all schemas in traversal order.
All []*SchemaInfo
// Components contains only component schemas.
Components []*SchemaInfo
// Inline contains only inline schemas (not in components).
Inline []*SchemaInfo
// ByPath provides lookup by JSON path.
ByPath map[string]*SchemaInfo
// ByName provides lookup by name for schemas in the components section.
// For top-level component schemas, this is the schema name (e.g., "Pet").
// For nested property schemas within components, this is the property name.
// Note: If multiple schemas have the same name, only the last one is stored.
ByName map[string]*SchemaInfo
}
SchemaCollector holds schemas collected during a walk.
func CollectSchemas ¶ added in v1.39.0
func CollectSchemas(result *parser.ParseResult) (*SchemaCollector, error)
CollectSchemas walks the document and collects all schemas. It returns a SchemaCollector containing all schemas organized by various criteria.
Example ¶
package main
import (
"fmt"
"github.com/erraggy/oastools/parser"
"github.com/erraggy/oastools/walker"
)
func main() {
doc := &parser.OAS3Document{
OpenAPI: "3.0.3",
Info: &parser.Info{Title: "Pet Store", Version: "1.0.0"},
Components: &parser.Components{
Schemas: map[string]*parser.Schema{
"Pet": {
Type: "object",
Description: "A pet in the store",
Properties: map[string]*parser.Schema{
"name": {Type: "string"},
},
},
"Error": {
Type: "object",
Description: "An error response",
},
},
},
}
result := &parser.ParseResult{
Document: doc,
OASVersion: parser.OASVersion303,
}
// Collect all schemas
schemas, _ := walker.CollectSchemas(result)
// Print component schema count
fmt.Printf("Total schemas: %d\n", len(schemas.All))
fmt.Printf("Component schemas: %d\n", len(schemas.Components))
// Look up by name
if pet, ok := schemas.ByName["Pet"]; ok {
fmt.Printf("Found Pet: %s\n", pet.Schema.Description)
}
}
Output: Total schemas: 3 Component schemas: 3 Found Pet: A pet in the store
type SchemaHandler ¶
type SchemaHandler func(wc *WalkContext, schema *parser.Schema) Action
SchemaHandler is called for each Schema, including nested schemas. The JSON path is available in wc.JSONPath. For named schemas, wc.Name contains the name.
type SchemaInfo ¶ added in v1.39.0
type SchemaInfo struct {
// Schema is the collected schema.
Schema *parser.Schema
// Name is the component name for component schemas.
// Empty for inline schemas.
Name string
// JSONPath is the full JSON path to the schema.
JSONPath string
// IsComponent is true when the schema is defined in components/definitions.
IsComponent bool
}
SchemaInfo contains information about a collected schema.
type SchemaPostHandler ¶ added in v1.39.0
type SchemaPostHandler func(wc *WalkContext, schema *parser.Schema)
SchemaPostHandler is called after a schema's children have been processed.
type SchemaSkippedHandler ¶
type SchemaSkippedHandler func(wc *WalkContext, reason string, schema *parser.Schema)
SchemaSkippedHandler is called when a schema is skipped due to depth limit or cycle detection. The reason parameter is either "depth" when the schema exceeds maxDepth, or "cycle" when the schema was already visited (circular reference detected). The schema parameter is the schema that was skipped. The JSON path is in wc.JSONPath.
type SecuritySchemeHandler ¶
type SecuritySchemeHandler func(wc *WalkContext, scheme *parser.SecurityScheme) Action
SecuritySchemeHandler is called for each SecurityScheme. The scheme name is available in wc.Name. The JSON path is in wc.JSONPath.
type ServerHandler ¶
type ServerHandler func(wc *WalkContext, server *parser.Server) Action
ServerHandler is called for each Server (OAS 3.x only). The JSON path is available in wc.JSONPath.
type TagHandler ¶
type TagHandler func(wc *WalkContext, tag *parser.Tag) Action
TagHandler is called for each Tag. The JSON path is available in wc.JSONPath.
type WalkContext ¶ added in v1.38.0
type WalkContext struct {
// JSONPath is the full JSON path to the current node.
// Always populated. Example: "$.paths['/pets'].get.responses['200']"
JSONPath string
// PathTemplate is the URL path template when walking within $.paths scope.
// Empty when not in paths scope. Example: "/pets/{petId}"
PathTemplate string
// Method is the HTTP method when walking within an operation scope.
// Empty when not in operation scope. Example: "get", "post"
Method string
// StatusCode is the HTTP status code when walking within a response scope.
// Empty when not in response scope. Example: "200", "default"
StatusCode string
// Name is the map key for named items like headers, schemas, examples, etc.
// Empty for array items or root-level objects. Example: "Pet", "X-Rate-Limit"
Name string
// IsComponent is true when the current node is within the components section
// (OAS 3.x) or definitions/parameters/responses at document root (OAS 2.x).
IsComponent bool
// CurrentRef is populated when the current node has a $ref.
// Only available when WithRefTracking() is enabled.
CurrentRef *RefInfo
// Parent provides access to the parent node, or nil at root.
// Only populated when WithParentTracking() option is used.
// Use helper methods like ParentSchema(), ParentOperation(), etc.
Parent *ParentInfo
// contains filtered or unexported fields
}
WalkContext provides contextual information about the current node being visited. It follows the http.Request pattern for context access.
IMPORTANT: WalkContext instances are reused via sync.Pool. Handlers must not retain references to WalkContext after returning from the handler function. If you need to preserve context information, copy the relevant fields to your own data structures before the handler returns.
func (*WalkContext) Ancestors ¶ added in v1.39.0
func (wc *WalkContext) Ancestors() []*ParentInfo
Ancestors returns all ancestors from immediate parent to root. The first element is the immediate parent, the last is the root-level ancestor. Returns nil if parent tracking is not enabled or there are no ancestors.
func (*WalkContext) Context ¶ added in v1.38.0
func (wc *WalkContext) Context() context.Context
Context returns the context.Context for cancellation and deadline propagation. Returns context.Background() if no context was set.
func (*WalkContext) Depth ¶ added in v1.39.0
func (wc *WalkContext) Depth() int
Depth returns the number of ancestors (nesting depth). Returns 0 if at root level or parent tracking is not enabled.
func (*WalkContext) InOperationScope ¶ added in v1.38.0
func (wc *WalkContext) InOperationScope() bool
InOperationScope returns true if currently walking within an operation.
func (*WalkContext) InPathsScope ¶ added in v1.38.0
func (wc *WalkContext) InPathsScope() bool
InPathsScope returns true if currently walking within $.paths.
func (*WalkContext) InResponseScope ¶ added in v1.38.0
func (wc *WalkContext) InResponseScope() bool
InResponseScope returns true if currently walking within a response.
func (*WalkContext) ParentOperation ¶ added in v1.39.0
func (wc *WalkContext) ParentOperation() (*parser.Operation, bool)
ParentOperation returns the nearest ancestor that is an Operation, if any. This is useful for determining which operation context a nested node belongs to.
func (*WalkContext) ParentPathItem ¶ added in v1.39.0
func (wc *WalkContext) ParentPathItem() (*parser.PathItem, bool)
ParentPathItem returns the nearest ancestor that is a PathItem, if any. This is useful for accessing path-level configuration from nested nodes.
func (*WalkContext) ParentRequestBody ¶ added in v1.39.0
func (wc *WalkContext) ParentRequestBody() (*parser.RequestBody, bool)
ParentRequestBody returns the nearest ancestor that is a RequestBody, if any. This is useful for determining if a schema is part of a request body.
func (*WalkContext) ParentResponse ¶ added in v1.39.0
func (wc *WalkContext) ParentResponse() (*parser.Response, bool)
ParentResponse returns the nearest ancestor that is a Response, if any. This is useful for determining which response a schema or header belongs to.
func (*WalkContext) ParentSchema ¶ added in v1.39.0
func (wc *WalkContext) ParentSchema() (*parser.Schema, bool)
ParentSchema returns the nearest ancestor that is a Schema, if any. This is useful for detecting when a schema is nested within another schema (e.g., a property within an object schema).
func (*WalkContext) WithContext ¶ added in v1.38.0
func (wc *WalkContext) WithContext(ctx context.Context) *WalkContext
WithContext returns a shallow copy of WalkContext with the new context.