validator

package
v1.5.0 Latest Latest
Warning

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

Go to latest
Published: Nov 16, 2025 License: MIT Imports: 7 Imported by: 0

Documentation

Overview

Package validator provides OpenAPI Specification (OAS) validation functionality.

This package validates OpenAPI specifications across multiple versions against their respective specification requirements. It performs structural validation, format checking, and semantic analysis to ensure API specifications are correct and conformant.

Supported Versions

The validator supports all official OpenAPI Specification releases:

All schema definitions are validated against JSON Schema Specification Draft 2020-12: https://www.ietf.org/archive/id/draft-bhutton-json-schema-01.html

Release candidate versions (e.g., 3.0.0-rc0) are detected but not officially supported.

Features

  • Multi-version support: Validates OAS 2.0 through OAS 3.2.0
  • Structural validation: Ensures required fields are present and properly formatted
  • Format validation: Validates URLs, emails, media types, HTTP status codes
  • Semantic validation: Checks operation ID uniqueness, path parameter consistency
  • Schema validation: Validates JSON schemas including type constraints and nested structures
  • Security validation: Validates security schemes and requirements
  • Best practice warnings: Optional recommendations for better API design
  • Strict mode: Additional validation beyond specification requirements

Validation Levels

The validator provides two severity levels for issues:

  • SeverityError: Specification violations that make the document invalid
  • SeverityWarning: Best practice violations or recommendations (optional)

Warnings can be suppressed by setting IncludeWarnings to false. Strict mode can be enabled to perform additional validation beyond spec requirements.

Validation Rules

The validator checks numerous aspects of OpenAPI documents:

Info Object:

  • Required fields: title, version
  • Format: Valid URLs for contact/license, valid email format

Paths:

  • Path patterns must start with "/"
  • Path templates must be well-formed (no empty braces, nested braces, etc.)
  • Path parameters must be declared and match template variables

Operations:

  • Operation IDs must be unique across the entire document
  • HTTP status codes must be valid (100-599 or wildcard patterns like "2XX")
  • Media types must follow RFC 2045/2046 format
  • Request bodies must have at least one media type (OAS 3.x)

Parameters:

  • Path parameters must have required: true
  • Body parameters must have a schema (OAS 2.0)
  • Non-body parameters must have a type (OAS 2.0)
  • Parameters must have either schema or content (OAS 3.x)

Schemas:

  • Array schemas must have 'items' defined
  • minLength/maxLength must be consistent
  • minimum/maximum must be consistent
  • Required fields must exist in properties
  • Enum values must match schema type

Security:

  • Security requirements must reference defined security schemes
  • Security schemes must have required fields for their type
  • OAuth2 flows must have required URLs

Security Considerations

The validator implements several protections:

  • Resource limits: Maximum schema nesting depth (100) to prevent stack overflow
  • Cycle detection: Prevents infinite loops in circular schema references
  • Format validation: Uses standard library parsing for URLs, media types, etc.
  • Input validation: All user-provided values are validated before processing

Basic Usage

For simple, one-off validation, use the convenience function:

result, err := validator.Validate("openapi.yaml", true, false)
if err != nil {
	log.Fatalf("Validation failed: %v", err)
}

if !result.Valid {
	fmt.Printf("Found %d error(s):\n", result.ErrorCount)
	for _, err := range result.Errors {
		fmt.Printf("  %s\n", err.String())
	}
}

For validating multiple files with the same configuration, create a Validator instance:

v := validator.New()
v.StrictMode = true
v.IncludeWarnings = true

result1, err := v.Validate("api1.yaml")
result2, err := v.Validate("api2.yaml")

Advanced Usage

Enable strict mode with warnings:

result, err := validator.Validate("openapi.yaml", true, true)
if err != nil {
	log.Fatalf("Validation failed: %v", err)
}

// Process errors
for _, verr := range result.Errors {
	fmt.Printf("ERROR: %s at %s\n", verr.Message, verr.Path)
	if verr.SpecRef != "" {
		fmt.Printf("  See: %s\n", verr.SpecRef)
	}
}

// Process warnings
for _, warn := range result.Warnings {
	fmt.Printf("WARNING: %s at %s\n", warn.Message, warn.Path)
}

Suppress warnings for production:

result, err := validator.Validate("openapi.yaml", false, false)
if err != nil {
	log.Fatalf("Validation failed: %v", err)
}

// Only errors will be reported
if !result.Valid {
	log.Printf("Validation failed with %d errors", result.ErrorCount)
}

Strict Mode

When StrictMode is enabled, the validator performs additional checks:

  • Warns about non-standard HTTP status codes (not defined in RFCs)
  • Warns if operations don't have at least one successful (2XX) response
  • May add additional best practice validations in future versions

Validation Output

The ValidationResult contains:

  • Valid: Boolean indicating if the document is valid (no errors)
  • Version: Detected OpenAPI version string (e.g., "3.0.3")
  • OASVersion: Enumerated OAS version for programmatic use
  • Errors: Slice of validation errors with paths and spec references
  • Warnings: Slice of validation warnings (if IncludeWarnings is true)
  • ErrorCount: Total number of errors
  • WarningCount: Total number of warnings

Each ValidationError contains:

  • Path: JSON path to the problematic field (e.g., "paths./pets.get.responses")
  • Message: Human-readable error description
  • SpecRef: URL to the relevant section of the OAS specification
  • Severity: Error or Warning
  • Field: Specific field name that has the issue (optional)
  • Value: The problematic value (optional)

Performance Notes

The validator performs comprehensive validation which may be resource-intensive for large documents. Performance considerations:

  • Schema validation: Deep schemas with many levels of nesting will take longer
  • Cycle detection: Maintains a visited map for each schema tree traversal
  • Operation ID checking: Requires scanning all operations in the document
  • Parameter consistency: Requires comparing path templates with parameter definitions

For better performance:

  • Validate documents during development rather than at runtime
  • Disable warnings (IncludeWarnings: false) if not needed
  • Disable strict mode if the additional checks aren't required
  • Cache validation results for unchanged documents

Error Path Format

Validation errors include a Path field that uses JSON path notation to identify the location of the issue:

  • "info.title" - Missing or invalid title in info object
  • "paths./pets.get.responses" - Issue with responses in GET /pets
  • "components.schemas.Pet.properties.name" - Issue with Pet.name property
  • "paths./users/{id}.get.parameters[0]" - Issue with first parameter

Common Validation Errors

Missing required fields:

  • "Info object must have a title"
  • "Info object must have a version"
  • "Response must have a description"

Format validation:

  • "Path must start with '/'"
  • "Invalid HTTP status code: 999"
  • "Invalid URL format: not-a-url"
  • "Invalid email format: invalid@@email"

Parameter issues:

  • "Path parameters must have required: true"
  • "Path template references parameter '{id}' but it is not declared"
  • "Body parameter must have a schema"

Schema validation:

  • "Array schema must have 'items' defined"
  • "minLength (10) cannot be greater than maxLength (5)"
  • "Required field 'name' not found in properties"

Limitations

  • External references: The validator validates the structure but does not follow or validate external $ref links
  • Custom validators: No support for custom validation rules or plugins
  • Schema keywords: Some advanced JSON Schema keywords may not be fully validated
  • OpenAPI extensions: Extension fields (x-*) are preserved but not validated

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Severity

type Severity int

Severity indicates the severity level of a validation issue

const (
	// SeverityError indicates a spec violation that makes the document invalid
	SeverityError Severity = iota
	// SeverityWarning indicates a best practice violation or recommendation
	SeverityWarning
)

func (Severity) String

func (s Severity) String() string

type ValidationError

type ValidationError struct {
	// Path is the JSON path to the problematic field (e.g., "paths./pets.get.responses")
	Path string
	// Message is a human-readable error message
	Message string
	// SpecRef is the URL to the relevant section of the OAS specification
	SpecRef string
	// Severity indicates whether this is an error or warning
	Severity Severity
	// Field is the specific field name that has the issue
	Field string
	// Value is the problematic value (optional)
	Value interface{}
}

ValidationError represents a single validation issue

func (ValidationError) String

func (e ValidationError) String() string

String returns a formatted string representation of the validation error

Example

ExampleValidationError_String demonstrates formatting of validation errors

package main

import (
	"fmt"

	"github.com/erraggy/oastools/validator"
)

func main() {
	err := validator.ValidationError{
		Path:     "paths./pets.get.responses",
		Message:  "Missing required field 'responses'",
		SpecRef:  "https://spec.openapis.org/oas/v3.0.0.html#operation-object",
		Severity: validator.SeverityError,
		Field:    "responses",
	}

	fmt.Println(err.String())
	// Output will show formatted error with path, message, and spec reference
}

type ValidationResult

type ValidationResult struct {
	// Valid is true if no errors were found (warnings are allowed)
	Valid bool
	// Version is the detected OAS version string
	Version string
	// OASVersion is the enumerated OAS version
	OASVersion parser.OASVersion
	// Errors contains all validation errors
	Errors []ValidationError
	// Warnings contains all validation warnings
	Warnings []ValidationError
	// ErrorCount is the total number of errors
	ErrorCount int
	// WarningCount is the total number of warnings
	WarningCount int
}

ValidationResult contains the results of validating an OpenAPI specification

Example

ExampleValidationResult demonstrates working with validation results

package main

import (
	"fmt"
	"log"
	"path/filepath"

	"github.com/erraggy/oastools/validator"
)

func main() {
	v := validator.New()
	testFile := filepath.Join("testdata", "invalid-oas3.yaml")

	result, err := v.Validate(testFile)
	if err != nil {
		log.Fatalf("Validation failed: %v", err)
	}

	// Check if document is valid
	if !result.Valid {
		fmt.Printf("Validation failed with %d error(s):\n", result.ErrorCount)
		for i, validationErr := range result.Errors {
			fmt.Printf("%d. %s: %s\n", i+1, validationErr.Path, validationErr.Message)
			if validationErr.SpecRef != "" {
				fmt.Printf("   See: %s\n", validationErr.SpecRef)
			}
		}
	}

	// Show warnings if any
	if result.WarningCount > 0 {
		fmt.Printf("\nWarnings (%d):\n", result.WarningCount)
		for i, warning := range result.Warnings {
			fmt.Printf("%d. %s: %s\n", i+1, warning.Path, warning.Message)
		}
	}
}

func Validate added in v1.4.0

func Validate(specPath string, includeWarnings, strictMode bool) (*ValidationResult, error)

Validate is a convenience function that validates an OpenAPI specification file with the specified options. It's equivalent to creating a Validator with New(), setting the options, and calling Validate().

For one-off validation operations, this function provides a simpler API. For validating multiple files with the same configuration, create a Validator instance and reuse it.

Example:

result, err := validator.Validate("openapi.yaml", true, false)
if err != nil {
    log.Fatal(err)
}
if !result.Valid {
    // Handle validation errors
}

func ValidateParsed added in v1.4.0

func ValidateParsed(parseResult parser.ParseResult, includeWarnings, strictMode bool) (*ValidationResult, error)

ValidateParsed is a convenience function that validates an already-parsed OpenAPI specification with the specified options.

Example:

parseResult, _ := parser.Parse("openapi.yaml", false, true)
result, err := validator.ValidateParsed(*parseResult, true, false)

type Validator

type Validator struct {
	// IncludeWarnings determines whether to include best practice warnings
	IncludeWarnings bool
	// StrictMode enables stricter validation beyond the spec requirements
	StrictMode bool
}

Validator handles OpenAPI specification validation

func New

func New() *Validator

New creates a new Validator instance with default settings

Example

ExampleNew demonstrates creating a new validator with default settings

package main

import (
	"fmt"

	"github.com/erraggy/oastools/validator"
)

func main() {
	// Create a validator with default settings
	v := validator.New()

	// Default settings
	fmt.Printf("Include warnings: %v\n", v.IncludeWarnings)
	fmt.Printf("Strict mode: %v\n", v.StrictMode)

}
Output:

Include warnings: true
Strict mode: false

func (*Validator) Validate

func (v *Validator) Validate(specPath string) (*ValidationResult, error)

Validate validates an OpenAPI specification file

Example

ExampleValidator_Validate demonstrates basic validation of an OpenAPI specification

package main

import (
	"fmt"
	"log"
	"path/filepath"

	"github.com/erraggy/oastools/validator"
)

func main() {
	// Create a new validator
	v := validator.New()

	// Validate a specification file
	testFile := filepath.Join("testdata", "petstore-3.0.yaml")
	result, err := v.Validate(testFile)
	if err != nil {
		log.Fatalf("Validation failed: %v", err)
	}

	// Check the results
	fmt.Printf("Valid: %v\n", result.Valid)
	fmt.Printf("Version: %s\n", result.Version)
	fmt.Printf("Errors: %d\n", result.ErrorCount)
	fmt.Printf("Warnings: %d\n", result.WarningCount)
}
Example (MultipleVersions)

ExampleValidator_Validate_multipleVersions demonstrates validating different OAS versions

package main

import (
	"fmt"
	"log"
	"path/filepath"

	"github.com/erraggy/oastools/validator"
)

func main() {
	v := validator.New()

	files := []string{
		"petstore-2.0.yaml",
		"petstore-3.0.yaml",
		"petstore-3.1.yaml",
		"petstore-3.2.yaml",
	}

	for _, file := range files {
		testFile := filepath.Join("testdata", file)
		result, err := v.Validate(testFile)
		if err != nil {
			log.Printf("Error validating %s: %v", file, err)
			continue
		}

		fmt.Printf("%s: Valid=%v, Version=%s, Errors=%d, Warnings=%d\n",
			file, result.Valid, result.Version, result.ErrorCount, result.WarningCount)
	}
}
Example (NoWarnings)

ExampleValidator_Validate_noWarnings demonstrates validation with warnings suppressed

package main

import (
	"fmt"
	"log"
	"path/filepath"

	"github.com/erraggy/oastools/validator"
)

func main() {
	// Create a validator that suppresses warnings
	v := validator.New()
	v.IncludeWarnings = false

	testFile := filepath.Join("testdata", "petstore-3.0.yaml")
	result, err := v.Validate(testFile)
	if err != nil {
		log.Fatalf("Validation failed: %v", err)
	}

	// Warnings will not be included in the result
	fmt.Printf("Valid: %v\n", result.Valid)
	fmt.Printf("Warnings count: %d\n", result.WarningCount)
}
Example (Oas2)

ExampleValidator_Validate_oas2 demonstrates validating an OAS 2.0 specification

package main

import (
	"fmt"
	"log"
	"path/filepath"

	"github.com/erraggy/oastools/validator"
)

func main() {
	v := validator.New()
	testFile := filepath.Join("testdata", "petstore-2.0.yaml")

	result, err := v.Validate(testFile)
	if err != nil {
		log.Fatalf("Validation failed: %v", err)
	}

	fmt.Printf("Valid OAS 2.0 document: %v\n", result.Valid)
	fmt.Printf("Version: %s\n", result.Version)
}
Example (StrictMode)

ExampleValidator_Validate_strictMode demonstrates validation with strict mode enabled

package main

import (
	"fmt"
	"log"
	"path/filepath"

	"github.com/erraggy/oastools/validator"
)

func main() {
	// Create a validator with strict mode
	v := validator.New()
	v.StrictMode = true

	testFile := filepath.Join("testdata", "petstore-3.0.yaml")
	result, err := v.Validate(testFile)
	if err != nil {
		log.Fatalf("Validation failed: %v", err)
	}

	// Strict mode may produce additional warnings
	fmt.Printf("Valid: %v\n", result.Valid)
	fmt.Printf("Errors: %d\n", result.ErrorCount)
	fmt.Printf("Warnings: %d\n", result.WarningCount)
}

func (*Validator) ValidateParsed added in v1.3.1

func (v *Validator) ValidateParsed(parseResult parser.ParseResult) (*ValidationResult, error)

ValidateParsed validates an already parsed OpenAPI specification

Example
package main

import (
	"fmt"
	"log"

	"github.com/erraggy/oastools/parser"
	"github.com/erraggy/oastools/validator"
)

func main() {
	// Parse once
	p := parser.New()
	parseResult, err := p.Parse("../testdata/petstore-3.0.yaml")
	if err != nil {
		log.Fatalf("Parse failed: %v", err)
	}

	// Validate the already-parsed document
	v := validator.New()
	v.StrictMode = true
	result, err := v.ValidateParsed(*parseResult)
	if err != nil {
		log.Fatalf("Validation failed: %v", err)
	}

	fmt.Printf("Valid: %v\n", result.Valid)
}

Jump to

Keyboard shortcuts

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