A Go library for parsing, validating, and generating code from AsyncAPI 3.0.0 documents.
- Full AsyncAPI 3.0.0 Support: Parse YAML and JSON documents
- Type-Safe API: Strongly-typed Go structs with the
*Refpattern for references - Validation: JSON Schema validation + semantic validation rules
- Reference Resolution: Local and external
$refresolution with cycle detection - Traits Merge: RFC 7386 JSON Merge Patch for operation and message traits
- Code Generation: Generate Go types, handlers, and clients from AsyncAPI specs
- Protocol Bindings: Support for HTTP, WebSocket, Kafka, AMQP, MQTT, NATS
- CLI Tool: Command-line interface for validation and code generation
go get github.com/belser/go-asyncapipackage main
import (
"fmt"
"log"
asyncapi "github.com/belser/go-asyncapi"
)
func main() {
// Load from file
doc, err := asyncapi.LoadFromFile("api.yaml")
if err != nil {
log.Fatal(err)
}
fmt.Printf("API: %s v%s\n", doc.Info.Title, doc.Info.Version)
// Iterate over channels
for name, ch := range doc.Channels {
if ch.Value != nil {
fmt.Printf("Channel: %s -> %s\n", name, *ch.Value.Address)
}
}
// Iterate over operations
for name, op := range doc.Operations {
if op.Value != nil {
fmt.Printf("Operation: %s (%s)\n", name, op.Value.Action)
}
}
}doc, err := asyncapi.LoadFromFile("api.yaml")
if err != nil {
log.Fatal(err)
}
// Full validation (JSON Schema + semantic rules)
if err := doc.Validate(); err != nil {
log.Fatal("Validation failed:", err)
}
// Or get detailed results
result := doc.ValidateAll()
for _, e := range result.Errors {
fmt.Printf("%s: %s\n", e.Path, e.Message)
}doc, err := asyncapi.LoadFromFile("api.yaml")
if err != nil {
log.Fatal(err)
}
// Resolve all $ref pointers
if err := doc.ResolveRefs(); err != nil {
log.Fatal(err)
}
// Now all references are populated
op := doc.Operations["userSignup"]
if op.Value != nil && op.Value.Channel.Value != nil {
fmt.Printf("Channel address: %s\n", *op.Value.Channel.Value.Address)
}doc, err := asyncapi.LoadFromFile("api.yaml")
if err != nil {
log.Fatal(err)
}
// Merge operation and message traits
if err := doc.MergeTraits(); err != nil {
log.Fatal(err)
}package main
import (
"log"
asyncapi "github.com/belser/go-asyncapi"
"github.com/belser/go-asyncapi/gen"
)
func main() {
doc, err := asyncapi.LoadFromFile("api.yaml")
if err != nil {
log.Fatal(err)
}
// Resolve refs and merge traits first
doc.ResolveRefs()
doc.MergeTraits()
// Generate code
g := gen.New().
WithPackage("myapi").
WithOutput("./generated")
if err := g.Generate(doc); err != nil {
log.Fatal(err)
}
}go build -o asyncapi ./cmd/asyncapiasyncapi validate api.yaml
# ✓ api.yaml is valid
# Schema-only validation
asyncapi validate --schema-only api.yaml
# Semantic-only validation
asyncapi validate --semantics-only api.yaml# Output as YAML
asyncapi parse api.yaml
# Output as JSON
asyncapi parse --format json api.yaml
# Resolve references first
asyncapi parse --resolve api.yaml# Generate to a directory
asyncapi generate --output ./gen --package api api.yaml
# Generate types only
asyncapi generate --output ./gen --types-only api.yamlThe library provides multiple ways to traverse the document for code generation:
doc, _ := asyncapi.LoadFromFile("api.yaml")
doc.ResolveRefs()
doc.Walk(&asyncapi.Visitor{
VisitSchema: func(name string, schema *asyncapi.Schema) bool {
fmt.Printf("Schema: %s\n", name)
if schema.IsObject() {
for propName, prop := range schema.SchemaProperties() {
fmt.Printf(" - %s: %v\n", propName, prop.Type)
}
}
return true // continue walking
},
VisitMessage: func(name string, msg *asyncapi.Message) bool {
fmt.Printf("Message: %s\n", name)
if payload := msg.PayloadSchema(); payload != nil {
// Generate message type from payload schema
}
return true
},
VisitOperation: func(name string, op *asyncapi.Operation) bool {
fmt.Printf("Operation: %s (%s)\n", name, op.Action)
return true
},
})doc, _ := asyncapi.LoadFromFile("api.yaml")
doc.ResolveRefs()
// Get all schemas for type generation
for name, schema := range doc.AllSchemas() {
generateType(name, schema)
}
// Get all messages
for _, msg := range doc.AllMessages() {
if payload := msg.PayloadSchema(); payload != nil {
generateMessageType(msg.Name, payload)
}
}
// Group operations by action
publishers, subscribers := doc.OperationsByAction()
for _, op := range publishers {
generatePublisher(op)
}
for _, op := range subscribers {
generateSubscriber(op)
}
// Get operations for a specific channel
ops := doc.ChannelOperations("userSignedup")schema := doc.AllSchemas()["User"]
if schema.IsObject() {
for name, prop := range schema.SchemaProperties() {
goType := schemaToGoType(prop)
fmt.Printf("%s %s\n", name, goType)
}
}
if schema.IsArray() {
itemSchema := schema.ItemSchema()
// Generate slice type
}The library uses the *Ref pattern (inspired by kin-openapi) for handling JSON References:
// ServerRef can be either a $ref or an inline Server
type ServerRef struct {
Ref string // The $ref URI (e.g., "#/components/servers/production")
Value *Server // The resolved/inline value
}When parsing, inline values populate Value directly. References set Ref and leave Value nil until ResolveRefs() is called.
Beyond JSON Schema validation, the library enforces these semantic rules:
- Unique operation IDs across all operations
- Channel
{param}placeholders must have corresponding parameter definitions - Server
{var}placeholders must have corresponding variable definitions - No duplicate tag names within the same object
- Valid runtime expression syntax (
$message.header#/...)
The library supports bindings for:
- HTTP
- WebSocket
- Kafka
- AMQP
- MQTT
- NATS
if op.Value.Bindings != nil && op.Value.Bindings.Value != nil {
if kafka := op.Value.Bindings.Value.Kafka; kafka != nil {
fmt.Printf("Kafka binding version: %s\n", kafka.BindingVersion)
}
}# Run all tests
go test ./...
# Run with verbose output
go test -v ./...
# Run fuzz tests
go test -fuzz=FuzzLoadFromData -fuzztime=30s .go-asyncapi/
├── asyncapi.go # Package documentation
├── document.go # Document type
├── info.go # Info, Contact, License
├── server.go # Server, ServerVariable
├── channel.go # Channel, Parameter
├── operation.go # Operation, OperationTrait
├── message.go # Message, MessageTrait
├── schema.go # JSON Schema types
├── security.go # SecurityScheme, OAuthFlows
├── bindings.go # Protocol bindings
├── components.go # Components object
├── reference.go # *Ref types
├── resolver.go # Reference resolution
├── validate.go # Validation logic
├── loader.go # File/URL loading
├── traits.go # Traits merge
├── runtime_expr.go # Runtime expression parser
├── errors.go # Error types
├── gen/ # Code generator
│ ├── generator.go
│ └── types.go
└── cmd/asyncapi/ # CLI tool
└── main.go
MIT