walker

package
v1.37.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jan 3, 2026 License: MIT Imports: 3 Imported by: 0

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(method string, op *parser.Operation, path string) 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(pathTemplate string, pathItem *parser.PathItem, path string) walker.Action {
        if strings.HasPrefix(pathTemplate, "/internal") {
            return walker.SkipChildren
        }
        return walker.Continue
    }),
)

Handler Types

The walker provides typed handlers for all major OAS node types:

Mutation Support

Handlers receive pointers to the actual nodes, so mutations are applied directly:

walker.Walk(result,
    walker.WithSchemaHandler(func(schema *parser.Schema, path string) walker.Action {
        if schema.Extra == nil {
            schema.Extra = make(map[string]any)
        }
        schema.Extra["x-processed"] = true
        return walker.Continue
    }),
)

JSON Path Context

Each handler receives a JSON path string indicating the node's location:

$.info                              // Info object
$.paths['/pets/{petId}']            // Path entry
$.paths['/pets'].get                // Operation
$.components.schemas['Pet']         // Schema

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).

Index

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(method string, op *parser.Operation, path string) 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(schema *parser.Schema, path string) 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(doc any, path string) 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(method string, op *parser.Operation, path string) walker.Action {
			fmt.Printf("Operation %s at: %s\n", op.OperationID, path)
			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(schema *parser.Schema, path string) 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(pathTemplate string, pathItem *parser.PathItem, path string) walker.Action {
			if pathTemplate == "/internal" {
				return walker.SkipChildren
			}
			return walker.Continue
		}),
		walker.WithOperationHandler(func(method string, op *parser.Operation, path string) 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(method string, op *parser.Operation, path string) walker.Action {
			firstOp = op.OperationID
			return walker.Stop
		}),
	)

	fmt.Println("First operation:", firstOp)
}
Output:

First operation: opA

func WalkWithOptions

func WalkWithOptions(opts ...WalkInputOption) error

WalkWithOptions walks a document using functional options for input and handlers.

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.OnSchema(func(schema *parser.Schema, path string) 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.

const (
	// Continue continues walking normally, visiting children and siblings.
	Continue Action = iota

	// SkipChildren skips all children of the current node but continues with siblings.
	SkipChildren

	// Stop stops the walk immediately. No more nodes will be visited.
	Stop
)

func (Action) IsValid

func (a Action) IsValid() bool

IsValid returns true if the action is one of the defined constants.

func (Action) String

func (a Action) String() string

String returns a string representation of the action.

type CallbackHandler

type CallbackHandler func(name string, callback parser.Callback, path string) Action

CallbackHandler is called for each Callback (OAS 3.x only).

type DocumentHandler

type DocumentHandler func(doc any, path string) Action

DocumentHandler is called for the root document (OAS2Document or OAS3Document).

type ExampleHandler

type ExampleHandler func(name string, example *parser.Example, path string) Action

ExampleHandler is called for each Example.

type ExternalDocsHandler

type ExternalDocsHandler func(extDocs *parser.ExternalDocs, path string) Action

ExternalDocsHandler is called for each ExternalDocs.

type HeaderHandler

type HeaderHandler func(name string, header *parser.Header, path string) Action

HeaderHandler is called for each Header.

type InfoHandler

type InfoHandler func(info *parser.Info, path string) Action

InfoHandler is called for the Info object.

type LinkHandler

type LinkHandler func(name string, link *parser.Link, path string) Action

LinkHandler is called for each Link (OAS 3.x only).

type MediaTypeHandler

type MediaTypeHandler func(mediaTypeName string, mt *parser.MediaType, path string) Action

MediaTypeHandler is called for each MediaType (OAS 3.x only).

type OAS2DocumentHandler

type OAS2DocumentHandler func(doc *parser.OAS2Document, path string) Action

OAS2DocumentHandler is called for OAS 2.0 (Swagger) documents.

type OAS3DocumentHandler

type OAS3DocumentHandler func(doc *parser.OAS3Document, path string) Action

OAS3DocumentHandler is called for OAS 3.x documents.

type OperationHandler

type OperationHandler func(method string, op *parser.Operation, path string) Action

OperationHandler is called for each Operation.

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 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 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

func WithMaxDepth(depth int) Option

WithMaxDepth sets the maximum recursion depth for schema traversal. Default is 100. If depth is <= 0, the default is kept.

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 WithParameterHandler

func WithParameterHandler(fn ParameterHandler) Option

WithParameterHandler sets the handler for Parameter objects.

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 WithRequestBodyHandler

func WithRequestBodyHandler(fn RequestBodyHandler) Option

WithRequestBodyHandler sets the handler for RequestBody objects (OAS 3.x only).

func WithResponseHandler

func WithResponseHandler(fn ResponseHandler) Option

WithResponseHandler sets the handler for Response objects.

func WithSchemaHandler

func WithSchemaHandler(fn SchemaHandler) Option

WithSchemaHandler sets the handler for Schema objects.

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(param *parser.Parameter, path string) Action

ParameterHandler is called for each Parameter.

type PathHandler

type PathHandler func(pathTemplate string, pathItem *parser.PathItem, path string) Action

PathHandler is called for each path entry with the path template string.

type PathItemHandler

type PathItemHandler func(pathItem *parser.PathItem, path string) Action

PathItemHandler is called for each PathItem.

type RequestBodyHandler

type RequestBodyHandler func(reqBody *parser.RequestBody, path string) Action

RequestBodyHandler is called for each RequestBody (OAS 3.x only).

type ResponseHandler

type ResponseHandler func(statusCode string, resp *parser.Response, path string) Action

ResponseHandler is called for each Response.

type SchemaHandler

type SchemaHandler func(schema *parser.Schema, path string) Action

SchemaHandler is called for each Schema, including nested schemas.

type SchemaSkippedHandler

type SchemaSkippedHandler func(reason string, schema *parser.Schema, path string)

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, and path is its JSON path.

type SecuritySchemeHandler

type SecuritySchemeHandler func(name string, scheme *parser.SecurityScheme, path string) Action

SecuritySchemeHandler is called for each SecurityScheme.

type ServerHandler

type ServerHandler func(server *parser.Server, path string) Action

ServerHandler is called for each Server (OAS 3.x only).

type TagHandler

type TagHandler func(tag *parser.Tag, path string) Action

TagHandler is called for each Tag.

type WalkInputOption

type WalkInputOption func(*walkConfig) error

WalkInputOption configures the WalkWithOptions function. Options may return an error for invalid configuration values (e.g., non-positive maxDepth).

func OnCallback

func OnCallback(fn CallbackHandler) WalkInputOption

OnCallback registers a handler for Callback objects.

func OnDocument

func OnDocument(fn DocumentHandler) WalkInputOption

OnDocument registers a handler for the root document.

func OnExample

func OnExample(fn ExampleHandler) WalkInputOption

OnExample registers a handler for Example objects.

func OnExternalDocs

func OnExternalDocs(fn ExternalDocsHandler) WalkInputOption

OnExternalDocs registers a handler for ExternalDocs objects.

func OnHeader

func OnHeader(fn HeaderHandler) WalkInputOption

OnHeader registers a handler for Header objects.

func OnInfo

func OnInfo(fn InfoHandler) WalkInputOption

OnInfo registers a handler for Info objects.

func OnLink(fn LinkHandler) WalkInputOption

OnLink registers a handler for Link objects.

func OnMediaType

func OnMediaType(fn MediaTypeHandler) WalkInputOption

OnMediaType registers a handler for MediaType objects.

func OnOAS2Document

func OnOAS2Document(fn OAS2DocumentHandler) WalkInputOption

OnOAS2Document registers a handler for OAS 2.0 (Swagger) documents. This handler is called before the generic DocumentHandler.

func OnOAS3Document

func OnOAS3Document(fn OAS3DocumentHandler) WalkInputOption

OnOAS3Document registers a handler for OAS 3.x documents. This handler is called before the generic DocumentHandler.

func OnOperation

func OnOperation(fn OperationHandler) WalkInputOption

OnOperation registers a handler for Operation objects.

func OnParameter

func OnParameter(fn ParameterHandler) WalkInputOption

OnParameter registers a handler for Parameter objects.

func OnPath

func OnPath(fn PathHandler) WalkInputOption

OnPath registers a handler for path entries.

func OnPathItem

func OnPathItem(fn PathItemHandler) WalkInputOption

OnPathItem registers a handler for PathItem objects.

func OnRequestBody

func OnRequestBody(fn RequestBodyHandler) WalkInputOption

OnRequestBody registers a handler for RequestBody objects.

func OnResponse

func OnResponse(fn ResponseHandler) WalkInputOption

OnResponse registers a handler for Response objects.

func OnSchema

func OnSchema(fn SchemaHandler) WalkInputOption

OnSchema registers a handler for Schema objects.

func OnSchemaSkipped

func OnSchemaSkipped(fn SchemaSkippedHandler) WalkInputOption

OnSchemaSkipped registers a handler called when schemas are skipped. The handler receives the reason ("depth" or "cycle"), the skipped schema, and its path.

func OnSecurityScheme

func OnSecurityScheme(fn SecuritySchemeHandler) WalkInputOption

OnSecurityScheme registers a handler for SecurityScheme objects.

func OnServer

func OnServer(fn ServerHandler) WalkInputOption

OnServer registers a handler for Server objects.

func OnTag

func OnTag(fn TagHandler) WalkInputOption

OnTag registers a handler for Tag objects.

func WithFilePath

func WithFilePath(path string) WalkInputOption

WithFilePath specifies a file path to parse and walk.

func WithMaxSchemaDepth

func WithMaxSchemaDepth(depth int) WalkInputOption

WithMaxSchemaDepth sets the maximum schema recursion depth. Returns an error if depth is not positive.

func WithParsed

func WithParsed(result *parser.ParseResult) WalkInputOption

WithParsed specifies a pre-parsed result to walk.

type Walker

type Walker struct {
	// contains filtered or unexported fields
}

Walker traverses OpenAPI documents and calls handlers for each node type.

func New

func New() *Walker

New creates a new Walker with default settings.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL