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
- WithOAS2DocumentPostHandler: Called after all OAS 2.0 document children processed
- WithOAS3DocumentPostHandler: Called after all OAS 3.x document 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
}),
)
For polymorphic schema fields that may contain map[string]any instead of *Schema (such as Items, AdditionalItems, AdditionalProperties, UnevaluatedItems, and UnevaluatedProperties), use WithMapRefTracking to also detect $ref values in those map structures.
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...)
Built-in Collectors ¶
For common collection patterns, the walker provides pre-built helpers that reduce boilerplate:
- CollectSchemas: Returns a SchemaCollector with all schemas indexed by name
- CollectOperations: Returns an OperationCollector with all operations indexed by path, method, and tag
- CollectParameters: Returns a ParameterCollector with all parameters indexed by name, location, and path
- CollectResponses: Returns a ResponseCollector with all responses indexed by status code and path
- CollectSecuritySchemes: Returns a SecuritySchemeCollector with all security schemes indexed by name
Example:
schemas, err := walker.CollectSchemas(result)
for name, info := range schemas.ByName {
fmt.Printf("Schema %s: %d properties\n", name, len(info.Schema.Properties))
}
ops, err := walker.CollectOperations(result)
for _, info := range ops.All {
fmt.Printf("%s %s -> %s\n", info.Method, info.PathTemplate, info.Operation.OperationID)
}
Each collector provides an All slice for ordered traversal and various maps for indexed lookup.
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 OAS2DocumentPostHandler
- type OAS3DocumentHandler
- type OAS3DocumentPostHandler
- 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 WithMapRefTracking() Option
- func WithMaxDepth(depth int) Optiondeprecated
- func WithMaxSchemaDepth(depth int) Option
- func WithMediaTypeHandler(fn MediaTypeHandler) Option
- func WithOAS2DocumentHandler(fn OAS2DocumentHandler) Option
- func WithOAS2DocumentPostHandler(fn OAS2DocumentPostHandler) Option
- func WithOAS3DocumentHandler(fn OAS3DocumentHandler) Option
- func WithOAS3DocumentPostHandler(fn OAS3DocumentPostHandler) 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 ParameterCollector
- type ParameterHandler
- type ParameterInfo
- type ParentInfo
- type PathHandler
- type PathItemHandler
- type PathItemPostHandler
- type RefHandler
- type RefInfo
- type RefNodeType
- type RequestBodyHandler
- type RequestBodyPostHandler
- type ResponseCollector
- type ResponseHandler
- type ResponseInfo
- type ResponsePostHandler
- type SchemaCollector
- type SchemaHandler
- type SchemaInfo
- type SchemaPostHandler
- type SchemaSkippedHandler
- type SecuritySchemeCollector
- type SecuritySchemeHandler
- type SecuritySchemeInfo
- 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 ¶
- CollectOperations
- CollectParameters
- CollectResponses
- CollectSchemas
- CollectSecuritySchemes
- Walk
- Walk (CollectSchemas)
- Walk (DocumentTypeSwitch)
- Walk (JsonPaths)
- Walk (Mutation)
- Walk (SkipChildren)
- Walk (Stop)
- WalkWithOptions
- WithMapRefTracking
- WithOAS2DocumentPostHandler
- WithOAS3DocumentPostHandler
- WithParentTracking
- WithRefHandler
- WithSchemaPostHandler
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 OAS2DocumentPostHandler ¶ added in v1.39.1
type OAS2DocumentPostHandler func(wc *WalkContext, doc *parser.OAS2Document)
OAS2DocumentPostHandler is called after all children of an OAS 2.0 document have been processed. This enables single-walk patterns where you collect information from operations/schemas and then modify the document based on that collection.
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 OAS3DocumentPostHandler ¶ added in v1.39.1
type OAS3DocumentPostHandler func(wc *WalkContext, doc *parser.OAS3Document)
OAS3DocumentPostHandler is called after all children of an OAS 3.x document have been processed. This enables single-walk patterns where you collect information from operations/schemas and then modify the document based on that collection.
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 WithMapRefTracking ¶ added in v1.39.2
func WithMapRefTracking() Option
WithMapRefTracking enables tracking of $ref values stored in map[string]any structures. When enabled, the walker will detect refs in polymorphic schema fields (Items, AdditionalItems, AdditionalProperties, UnevaluatedItems, UnevaluatedProperties) that were not parsed as *Schema. Implicitly enables ref tracking.
Polymorphic fields may contain map[string]any instead of *Schema when:
- Documents are parsed from raw YAML/JSON without full schema resolution
- Manually constructing documents with map literals (e.g., in tests)
- Using external tooling that produces partially resolved documents
The walker will call the ref handler for any $ref values found in these map structures.
Example ¶
package main
import (
"fmt"
"github.com/erraggy/oastools/parser"
"github.com/erraggy/oastools/walker"
)
func main() {
// Some polymorphic schema fields (Items, AdditionalItems, AdditionalProperties,
// UnevaluatedItems, UnevaluatedProperties) can contain map[string]any instead of
// *parser.Schema in certain parsing scenarios. WithMapRefTracking enables
// detection of $ref values stored in these map structures.
doc := &parser.OAS3Document{
OpenAPI: "3.1.0",
Info: &parser.Info{Title: "Test", Version: "1.0.0"},
Components: &parser.Components{
Schemas: map[string]*parser.Schema{
"Container": {
Type: "array",
// Simulating Items as map[string]any with a $ref (can occur in some parsing scenarios)
Items: map[string]any{
"$ref": "#/components/schemas/Item",
},
},
"Item": {Type: "string"},
},
},
}
result := &parser.ParseResult{
Document: doc,
OASVersion: parser.OASVersion310,
}
var refs []string
_ = walker.Walk(result,
walker.WithMapRefTracking(), // Enable detection of refs in map structures
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/Item
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 WithOAS2DocumentPostHandler ¶ added in v1.39.1
func WithOAS2DocumentPostHandler(fn OAS2DocumentPostHandler) Option
WithOAS2DocumentPostHandler sets a handler called after all children of an OAS 2.0 document have been processed. This enables single-walk patterns where you collect information from operations, schemas, or other children and then modify the document based on that collection. Not called if the document pre-visit handler returns SkipChildren or Stop.
Example ¶
package main
import (
"fmt"
"github.com/erraggy/oastools/parser"
"github.com/erraggy/oastools/walker"
)
func main() {
doc := &parser.OAS2Document{
Swagger: "2.0",
Info: &parser.Info{Title: "Legacy API", Version: "1.0.0"},
Paths: parser.Paths{
"/items": &parser.PathItem{
Get: &parser.Operation{OperationID: "listItems"},
Put: &parser.Operation{OperationID: "updateItems"},
},
},
Definitions: map[string]*parser.Schema{
"Item": {Type: "object"},
"Error": {Type: "object"},
},
}
result := &parser.ParseResult{
Document: doc,
OASVersion: parser.OASVersion20,
}
// Collect statistics during walk, then summarize in post handler
var schemaCount, operationCount int
_ = walker.Walk(result,
walker.WithSchemaHandler(func(wc *walker.WalkContext, schema *parser.Schema) walker.Action {
schemaCount++
return walker.Continue
}),
walker.WithOperationHandler(func(wc *walker.WalkContext, op *parser.Operation) walker.Action {
operationCount++
return walker.Continue
}),
walker.WithOAS2DocumentPostHandler(func(wc *walker.WalkContext, d *parser.OAS2Document) {
// Called after ALL children have been processed
fmt.Printf("Swagger %s: %s\n", d.Swagger, d.Info.Title)
fmt.Printf("Schemas: %d, Operations: %d\n", schemaCount, operationCount)
}),
)
}
Output: Swagger 2.0: Legacy API Schemas: 2, Operations: 2
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 WithOAS3DocumentPostHandler ¶ added in v1.39.1
func WithOAS3DocumentPostHandler(fn OAS3DocumentPostHandler) Option
WithOAS3DocumentPostHandler sets a handler called after all children of an OAS 3.x document have been processed. This enables single-walk patterns where you collect information from operations, schemas, or other children and then modify the document based on that collection. Not called if the document pre-visit handler returns SkipChildren or Stop.
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"}},
},
"/users": &parser.PathItem{
Get: &parser.Operation{OperationID: "listUsers", Tags: []string{"users"}},
},
},
}
result := &parser.ParseResult{
Document: doc,
OASVersion: parser.OASVersion303,
}
// Collect operations during walk, then use the document post handler
// to add a summary based on collected data. This is the "single-walk" pattern.
var operationCount int
tagCounts := make(map[string]int)
_ = walker.Walk(result,
walker.WithOperationHandler(func(wc *walker.WalkContext, op *parser.Operation) walker.Action {
operationCount++
for _, tag := range op.Tags {
tagCounts[tag]++
}
return walker.Continue
}),
walker.WithOAS3DocumentPostHandler(func(wc *walker.WalkContext, d *parser.OAS3Document) {
// Called after ALL children have been processed
// Perfect for aggregating collected data
fmt.Printf("Document: %s\n", d.Info.Title)
fmt.Printf("Total operations: %d\n", operationCount)
fmt.Printf("Operations by tag: pets=%d, users=%d\n", tagCounts["pets"], tagCounts["users"])
}),
)
}
Output: Document: Pet Store Total operations: 3 Operations by tag: pets=2, users=1
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 ParameterCollector ¶ added in v1.50.0
type ParameterCollector struct {
// All contains all parameters in traversal order.
All []*ParameterInfo
// ByName groups parameters by name.
ByName map[string][]*ParameterInfo
// ByLocation groups parameters by location: "query", "header", "path", "cookie".
ByLocation map[string][]*ParameterInfo
// ByPath groups parameters by path template.
ByPath map[string][]*ParameterInfo
}
ParameterCollector holds parameters collected during a walk.
func CollectParameters ¶ added in v1.50.0
func CollectParameters(result *parser.ParseResult) (*ParameterCollector, error)
CollectParameters walks the document and collects all parameters. It returns a ParameterCollector containing all parameters 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",
Parameters: []*parser.Parameter{
{Name: "limit", In: "query"},
{Name: "offset", In: "query"},
},
},
},
"/pets/{petId}": &parser.PathItem{
Parameters: []*parser.Parameter{
{Name: "petId", In: "path", Required: true},
},
Get: &parser.Operation{
OperationID: "getPet",
},
},
},
}
result := &parser.ParseResult{
Document: doc,
OASVersion: parser.OASVersion303,
}
params, _ := walker.CollectParameters(result)
fmt.Printf("Total parameters: %d\n", len(params.All))
fmt.Printf("Query parameters: %d\n", len(params.ByLocation["query"]))
fmt.Printf("Path parameters: %d\n", len(params.ByLocation["path"]))
}
Output: Total parameters: 3 Query parameters: 2 Path parameters: 1
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 ParameterInfo ¶ added in v1.50.0
type ParameterInfo struct {
// Parameter is the collected parameter.
Parameter *parser.Parameter
// Name is the parameter name.
Name string
// In is the parameter location: query, header, path, cookie.
In string
// JSONPath is the full JSON path to the parameter.
JSONPath string
// PathTemplate is the owning path template.
PathTemplate string
// Method is the owning operation method (empty if path-level).
Method string
// IsComponent is true when the parameter is defined in components/definitions.
IsComponent bool
}
ParameterInfo contains information about a collected parameter.
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 ResponseCollector ¶ added in v1.50.0
type ResponseCollector struct {
// All contains all responses in traversal order.
All []*ResponseInfo
// ByStatusCode groups responses by HTTP status code.
ByStatusCode map[string][]*ResponseInfo
// ByPath groups responses by path template.
ByPath map[string][]*ResponseInfo
}
ResponseCollector holds responses collected during a walk.
func CollectResponses ¶ added in v1.50.0
func CollectResponses(result *parser.ParseResult) (*ResponseCollector, error)
CollectResponses walks the document and collects all responses. It returns a ResponseCollector containing all responses 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",
Responses: &parser.Responses{
Codes: map[string]*parser.Response{
"200": {Description: "A list of pets"},
"500": {Description: "Server error"},
},
},
},
Post: &parser.Operation{
OperationID: "createPet",
Responses: &parser.Responses{
Codes: map[string]*parser.Response{
"201": {Description: "Pet created"},
},
},
},
},
},
}
result := &parser.ParseResult{
Document: doc,
OASVersion: parser.OASVersion303,
}
responses, _ := walker.CollectResponses(result)
fmt.Printf("Total responses: %d\n", len(responses.All))
fmt.Printf("Success (200): %d\n", len(responses.ByStatusCode["200"]))
fmt.Printf("Server errors (500): %d\n", len(responses.ByStatusCode["500"]))
}
Output: Total responses: 3 Success (200): 1 Server errors (500): 1
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 ResponseInfo ¶ added in v1.50.0
type ResponseInfo struct {
// Response is the collected response.
Response *parser.Response
// StatusCode is the HTTP status code (e.g., "200", "404", "default").
StatusCode string
// JSONPath is the full JSON path to the response.
JSONPath string
// PathTemplate is the owning path template.
PathTemplate string
// Method is the owning operation method.
Method string
// IsComponent is true when the response is defined in components/responses.
IsComponent bool
}
ResponseInfo contains information about a collected response.
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 SecuritySchemeCollector ¶ added in v1.50.0
type SecuritySchemeCollector struct {
// All contains all security schemes in traversal order.
All []*SecuritySchemeInfo
// ByName provides lookup by name.
ByName map[string]*SecuritySchemeInfo
}
SecuritySchemeCollector holds security schemes collected during a walk.
func CollectSecuritySchemes ¶ added in v1.50.0
func CollectSecuritySchemes(result *parser.ParseResult) (*SecuritySchemeCollector, error)
CollectSecuritySchemes walks the document and collects all security schemes. It returns a SecuritySchemeCollector containing all security schemes 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{
SecuritySchemes: map[string]*parser.SecurityScheme{
"bearerAuth": {
Type: "http",
Scheme: "bearer",
},
"apiKey": {
Type: "apiKey",
Name: "X-API-Key",
In: "header",
},
},
},
}
result := &parser.ParseResult{
Document: doc,
OASVersion: parser.OASVersion303,
}
schemes, _ := walker.CollectSecuritySchemes(result)
fmt.Printf("Total schemes: %d\n", len(schemes.All))
if bearer, ok := schemes.ByName["bearerAuth"]; ok {
fmt.Printf("bearerAuth: type=%s, scheme=%s\n", bearer.SecurityScheme.Type, bearer.SecurityScheme.Scheme)
}
}
Output: Total schemes: 2 bearerAuth: type=http, scheme=bearer
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 SecuritySchemeInfo ¶ added in v1.50.0
type SecuritySchemeInfo struct {
// SecurityScheme is the collected security scheme.
SecurityScheme *parser.SecurityScheme
// Name is the security scheme name from the components map key.
Name string
// JSONPath is the full JSON path to the security scheme.
JSONPath string
}
SecuritySchemeInfo contains information about a collected security scheme.
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.