libasyncapi

package module
v0.0.2 Latest Latest
Warning

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

Go to latest
Published: Jul 12, 2026 License: MIT Imports: 14 Imported by: 0

README

libasyncapi - high-performance AsyncAPI tools for Go

Go Reference License

libasyncapi parses AsyncAPI 3.0+ documents into strongly typed Go models. It provides a high-level API for normal application work and a low-level, YAML-aware API for tooling that needs source nodes, line and column numbers, key ordering, references, or render fidelity.

AsyncAPI 2.x is intentionally unsupported.


Features

  • AsyncAPI 3.0+ parsing with high-level and low-level models.
  • Lenient partial parsing with accumulated diagnostics.
  • Local and remote multi-file reference resolution.
  • Ordered maps and access to the original YAML node tree.
  • Model rendering and original-document serialization.
  • Visitor-based document traversal, including schemas and protocol bindings.
  • Breaking and non-breaking change detection through what-changed.
  • Typed HTTP, Kafka, WebSocket, AMQP, MQTT, and SQS bindings.

Install

go get github.com/pb33f/libasyncapi

Quick start

package main

import (
	"fmt"
	"log"

	"github.com/pb33f/libasyncapi"
)

func main() {
	spec := []byte(`asyncapi: 3.0.0
info:
  title: Orders API
  version: 1.0.0
channels:
  orders:
    address: /orders
`)

	doc, err := libasyncapi.NewDocument(spec)
	if err != nil {
		log.Fatal(err)
	}

	model := doc.Model()
	fmt.Printf("%s uses AsyncAPI %s\n", model.Info.Title, doc.GetVersion())
	for name, channel := range model.Channels.FromOldest() {
		if channel.Address != nil {
			fmt.Printf("channel %s: %s\n", name, *channel.Address)
		}
	}
}

Output:

Orders API uses AsyncAPI 3.0.0
channel orders: /orders

Partial documents and diagnostics

Parsing continues where possible. A document can therefore contain a useful partial model and one or more diagnostics:

doc, err := libasyncapi.NewDocument(spec)
if err != nil {
	log.Fatal(err) // The document could not be created at all.
}

if doc.IsPartial() {
	for _, parseErr := range doc.Errors() {
		log.Printf("AsyncAPI diagnostic: %v", parseErr)
	}
}

High-level and low-level models

Use Model() for ordinary application logic:

model := doc.Model()
fmt.Println(model.Info.Title)

Use GoLow() when source information matters:

lowModel := doc.GoLow()
fmt.Println(lowModel.Info.Value.Title.KeyNode.Line)

Every high-level model type exposes GoLow() and GoLowUntyped() for moving back to its source-aware representation.

Multi-file documents

External references are disabled by default. Enable only the reference types your application needs:

config := libasyncapi.NewDocumentConfiguration()
config.BasePath = "/path/to/asyncapi"
config.AllowFileReferences = true
config.AllowRemoteReferences = false

doc, err := libasyncapi.NewDocumentWithConfiguration(spec, config)

Rendering and serialization

Render() writes the current high-level model. Serialize() writes the original YAML tree:

rendered, err := doc.Render()
original, err := doc.Serialize()

Compare documents

The what-changed package produces a hierarchical change model with breaking-change classification:

import what_changed "github.com/pb33f/libasyncapi/what-changed"

changes := what_changed.CompareDocuments(originalDoc, updatedDoc)
if changes != nil {
	fmt.Printf("%d changes, %d breaking\n",
		changes.TotalChanges(), changes.TotalBreakingChanges())
}

Documentation and support

The public Go API is documented at pkg.go.dev/github.com/pb33f/libasyncapi. Full project documentation and a dedicated logo have not been published yet.

Need help, have a question, or want to share what you are building? Join the pb33f Discord.

License

libasyncapi is released under the MIT License.

Documentation

Overview

Package libasyncapi is a library containing tools for reading and manipulating AsyncAPI 3+ specifications into strongly typed documents. These documents have two APIs, a high level (porcelain) and a low level (plumbing).

Every single type has a 'GoLow()' method that drops down from the high API to the low API. Once in the low API, the entire original document data is available, including all comments, line and column numbers for keys and values.

Supported Versions

This library supports AsyncAPI 3.0 and later. AsyncAPI 2.x specifications are not supported and will return ErrAsyncAPI2NotSupported.

Basic Usage

spec, err := os.ReadFile("asyncapi.yaml")
if err != nil {
    log.Fatal(err)
}

doc, err := libasyncapi.NewDocument(spec)
if err != nil {
    log.Fatal(err)
}

model := doc.Model()
fmt.Printf("API: %s\n", model.Info.Title)

Error Handling

The library uses lenient parsing - it accumulates errors and continues parsing where possible. Use doc.IsPartial() to check if errors occurred, and doc.Errors() to retrieve them. The model may still be usable even with errors.

Multi-File Specifications

For specifications split across multiple files, use NewDocumentWithConfiguration and set the BasePath to enable file reference resolution:

config := libasyncapi.NewDocumentConfiguration()
config.BasePath = "/path/to/spec/directory"
config.AllowFileReferences = true

doc, err := libasyncapi.NewDocumentWithConfiguration(spec, config)

Index

Examples

Constants

This section is empty.

Variables

View Source
var ErrAsyncAPI2NotSupported = errors.New("AsyncAPI 2.x is not supported; use AsyncAPI 3.0 or later")

ErrAsyncAPI2NotSupported is returned when attempting to parse an AsyncAPI 2.x specification. This library only supports AsyncAPI 3.0 and later.

View Source
var ErrInvalidAsyncAPIVersion = errors.New("asyncapi version is not a valid semver string")

ErrInvalidAsyncAPIVersion is returned when the asyncapi version field is not a valid semver string.

View Source
var ErrInvalidYAML = errors.New("specification is not valid YAML or JSON")

ErrInvalidYAML is returned when the specification is not valid YAML or JSON.

View Source
var ErrNoAsyncAPIVersion = errors.New("asyncapi version field is required")

ErrNoAsyncAPIVersion is returned when the asyncapi version field is missing from the specification.

Functions

func DefaultSchemaFormat

func DefaultSchemaFormat(asyncapiVersion string) string

DefaultSchemaFormat returns the default schema format for a given AsyncAPI version. Per the spec, when schemaFormat is omitted, it defaults to the AsyncAPI schema format with the version matching the document's asyncapi field.

func DetectAsyncAPIVersion

func DetectAsyncAPIVersion(spec []byte) (string, error)

DetectAsyncAPIVersion extracts and validates the asyncapi version from a specification. It returns the version string and any error encountered. If the specification is AsyncAPI 2.x, it returns ErrAsyncAPI2NotSupported.

func ExtractVersionFromNode

func ExtractVersionFromNode(rootNode *yaml.Node) (string, error)

ExtractVersionFromNode extracts the asyncapi version from an already-parsed YAML node. This avoids double-parsing when the document has already been unmarshaled.

func IsAsyncAPI3

func IsAsyncAPI3(version string) bool

IsAsyncAPI3 checks if the given version string represents AsyncAPI 3.x.

Types

type CircularReferenceError

type CircularReferenceError struct {
	Path  string
	Chain []string
}

CircularReferenceError represents a circular reference detected in the specification.

func NewCircularReferenceError

func NewCircularReferenceError(path string, chain []string) *CircularReferenceError

NewCircularReferenceError creates a new CircularReferenceError.

func (*CircularReferenceError) Error

func (e *CircularReferenceError) Error() string

Error implements the error interface.

type Document

type Document interface {
	// GetVersion will return the exact version of the AsyncAPI specification set for the document.
	GetVersion() string

	// GetSpecInfo will return the SpecInfo instance that contains all specification information.
	GetSpecInfo() *SpecInfo

	// Model returns the high-level AsyncAPI model.
	// Returns nil if parsing completely failed.
	Model() *highasync.AsyncAPI

	// GoLow returns the low-level AsyncAPI model.
	// This provides access to line/column numbers and raw YAML nodes.
	GoLow() *lowasync.AsyncAPI

	// Index returns the reference index for this document.
	Index() *index.SpecIndex

	// Rolodex returns the file management system for multi-file specs.
	Rolodex() *index.Rolodex

	// RootNode returns the original YAML tree (not normalized).
	// This provides raw access for tooling that needs the original structure.
	RootNode() *yaml.Node

	// Serialize marshals the original YAML root node back to bytes.
	// This preserves the original structure and formatting.
	// For model-based rendering, use Render() instead.
	Serialize() ([]byte, error)

	// Render will return a YAML representation of the high-level model.
	Render() ([]byte, error)

	// Errors returns all errors accumulated during parsing.
	// The document may still contain a partial model even if errors occurred.
	Errors() []error

	// IsPartial returns true if errors occurred during parsing.
	// When true, the model may be incomplete but still usable.
	IsPartial() bool
}

Document represents a parsed AsyncAPI document that can be rendered into a model or serialized.

func NewDocument

func NewDocument(spec []byte) (Document, error)

NewDocument will create a new AsyncAPI instance from an AsyncAPI specification []byte array. If anything goes wrong when parsing, reading or processing the specification, there will be no document returned, instead an error will be returned that explains what failed.

This function will NOT automatically follow (meaning load) any file or remote references. If you need to load external references, use NewDocumentWithConfiguration instead.

Example
package main

import (
	"fmt"
	"log"

	"github.com/pb33f/libasyncapi"
)

func main() {
	spec := []byte(`asyncapi: 3.0.0
info:
  title: Orders API
  version: 1.0.0
channels:
  orders:
    address: /orders
`)

	doc, err := libasyncapi.NewDocument(spec)
	if err != nil {
		log.Fatal(err)
	}

	model := doc.Model()
	fmt.Printf("%s uses AsyncAPI %s\n", model.Info.Title, doc.GetVersion())
	for name, channel := range model.Channels.FromOldest() {
		if channel.Address != nil {
			fmt.Printf("channel %s: %s\n", name, *channel.Address)
		}
	}

}
Output:
Orders API uses AsyncAPI 3.0.0
channel orders: /orders

func NewDocumentWithConfiguration

func NewDocumentWithConfiguration(spec []byte, config *DocumentConfiguration) (Document, error)

NewDocumentWithConfiguration is the same as NewDocument, except it accepts a configuration that allows control over file and remote reference resolution.

type DocumentConfiguration

type DocumentConfiguration struct {
	// BasePath is the base path for resolving relative file references.
	// If empty, the current working directory is used.
	BasePath string

	// BaseURL is the base URL for resolving relative URL references.
	BaseURL *url.URL

	// AllowFileReferences enables resolution of file:// references.
	// Defaults to false.
	AllowFileReferences bool

	// AllowRemoteReferences enables resolution of http:// and https:// references.
	// Defaults to false.
	AllowRemoteReferences bool

	// RemoteURLHandler is a custom function for fetching remote references.
	// If nil, the default http client is used.
	RemoteURLHandler func(url string) (*http.Response, error)

	// LocalFS is a custom filesystem for resolving local file references.
	// If nil, the OS filesystem is used.
	LocalFS fs.FS

	// SkipCircularReferenceCheck disables circular reference detection.
	// This can improve performance but may cause infinite loops if circular
	// references exist in the specification.
	SkipCircularReferenceCheck bool

	// ExtractRefsSequentially processes references one at a time instead of
	// in parallel. This is slower but can be useful for debugging.
	ExtractRefsSequentially bool

	// Logger is an optional structured logger for diagnostic messages.
	Logger *slog.Logger
}

DocumentConfiguration holds configuration options for parsing AsyncAPI documents.

func NewDocumentConfiguration

func NewDocumentConfiguration() *DocumentConfiguration

NewDocumentConfiguration creates a new DocumentConfiguration with default values.

func (*DocumentConfiguration) ToLibOpenAPIConfig

func (c *DocumentConfiguration) ToLibOpenAPIConfig() *datamodel.DocumentConfiguration

ToLibOpenAPIConfig converts this configuration to libopenapi's configuration format.

type ParseError

type ParseError struct {
	Message string
	Line    int
	Column  int
	Path    string
}

ParseError represents an error that occurred during parsing with location information.

func NewParseError

func NewParseError(message string, line, column int, path string) *ParseError

NewParseError creates a new ParseError with the given message and location.

func (*ParseError) Error

func (e *ParseError) Error() string

Error implements the error interface.

type ReferenceError

type ReferenceError struct {
	Reference string
	Message   string
	Line      int
	Column    int
}

ReferenceError represents an error resolving a $ref reference.

func NewReferenceError

func NewReferenceError(ref, message string, line, column int) *ReferenceError

NewReferenceError creates a new ReferenceError.

func (*ReferenceError) Error

func (e *ReferenceError) Error() string

Error implements the error interface.

type SpecInfo

type SpecInfo struct {
	Version       string
	VersionParsed *semver.Version
	SpecType      string
}

SpecInfo contains parsed version information from an AsyncAPI specification.

func ParseAsyncAPIVersion

func ParseAsyncAPIVersion(version string) (*SpecInfo, error)

ParseAsyncAPIVersion parses a version string and returns SpecInfo. It validates that the version is a valid semver and is AsyncAPI 3.x.

type ValidationError

type ValidationError struct {
	Message string
	Path    string
}

ValidationError represents a semantic validation error in the specification.

func NewValidationError

func NewValidationError(message, path string) *ValidationError

NewValidationError creates a new ValidationError.

func (*ValidationError) Error

func (e *ValidationError) Error() string

Error implements the error interface.

Directories

Path Synopsis
datamodel
Package visitor provides a visitor pattern for traversing AsyncAPI 3.0 documents.
Package visitor provides a visitor pattern for traversing AsyncAPI 3.0 documents.
Package what_changed determines what changed between two AsyncAPI documents.
Package what_changed determines what changed between two AsyncAPI documents.
model
Package model contains all the comparison logic and change types used to determine what changed between two AsyncAPI documents.
Package model contains all the comparison logic and change types used to determine what changed between two AsyncAPI documents.
reports
Package reports provides summarized, flattened views over the hierarchical change trees produced by the what-changed model.
Package reports provides summarized, flattened views over the hierarchical change trees produced by the what-changed model.

Jump to

Keyboard shortcuts

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