asyncapi3

package module
v0.1.0 Latest Latest
Warning

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

Go to latest
Published: Jul 28, 2026 License: Apache-2.0 Imports: 10 Imported by: 0

README

asyncapi3

CI Go Reference

Code-first AsyncAPI 3.0 document generation for Go. Declare servers, channels, and operations as Go values, reflect payload schemas from the structs that actually cross the wire, and emit a document that validates against the official meta-schema.

As of July 2026 the existing Go libraries either generate 2.4.0 documents from code or generate code from a 3.0 document — see comparison. This one generates 3.0 documents from code.

go get github.com/mitresthen/asyncapi3

Quickstart

package main

import (
	"encoding/json"
	"fmt"
	"time"

	"github.com/mitresthen/asyncapi3"
)

type PortTotals struct {
	UnloCode    string    `json:"unloCode"    required:"true"`
	ActivePower float64   `json:"activePower" required:"true"`
	MeasuredAt  time.Time `json:"measuredAt"  required:"true"`
}

func main() {
	payload, schemas, err := asyncapi3.SchemaFromType(PortTotals{})
	if err != nil {
		panic(err)
	}

	doc := asyncapi3.New("Port Telemetry", "1.0.0")
	doc.DefaultContentType = "application/json"
	doc.Servers = map[string]asyncapi3.Server{
		"production": {Host: "telemetry.example.com", Protocol: "wss"},
	}
	doc.Channels = map[string]asyncapi3.Channel{
		"portTotals": {
			Address:     "/ports/{unlocode}",
			Description: "Live totals, broadcast every 5 seconds.",
			Parameters: map[string]asyncapi3.Parameter{
				"unlocode": {Description: "Port UNLOCODE."},
			},
			Messages: map[string]asyncapi3.Message{
				"portTotals": {Ref: "#/components/messages/portTotals"},
			},
		},
	}
	doc.Operations = map[string]asyncapi3.Operation{
		"receivePortTotals": {
			Action:   asyncapi3.ActionReceive,
			Channel:  asyncapi3.Ref("#/channels/portTotals"),
			Messages: []asyncapi3.RefObj{asyncapi3.Ref("#/channels/portTotals/messages/portTotals")},
		},
	}
	doc.Components = &asyncapi3.Components{
		Schemas:  schemas,
		Messages: map[string]asyncapi3.Message{"portTotals": {Name: "PortTotals", Payload: payload}},
	}

	if err := doc.Validate(); err != nil {
		panic(err)
	}

	out, err := json.MarshalIndent(doc, "", "  ")
	if err != nil {
		panic(err)
	}

	fmt.Println(string(out))
}

Runnable versions live in examples/.

What it gives you

Deterministic output. Maps marshal key-sorted and struct field order is fixed, so regenerating an unchanged document is byte-identical. That is what makes the contract gateable in CI: commit the document, regenerate it on every build, and fail on any diff. Check does exactly that comparison and returns an actionable error:

// in your generator's main(), behind a --check flag
if err := asyncapi3.Check(generated, "api/asyncapi.json"); err != nil {
	log.Fatal(err) // "api/asyncapi.json is stale vs the generator output …"
}

Conformance you can trust. Document.Validate() checks the marshalled document against the official AsyncAPI 3.0.0 meta-schema, embedded in the module — no network access, no separate toolchain. The library's own test suite additionally validates its output with the official @asyncapi/cli parser, so two independent validators agree.

Schema fidelity. Payload schemas are json.RawMessage, injected verbatim from the schema source. Nothing in this library re-interprets them. The default source is swaggest/jsonschema-go reflection, with definitions collected under #/components/schemas/.

Room to escape. Spec objects and protocol bindings that are not modelled yet attach as raw JSON through the Bindings json.RawMessage fields, so an unmodelled binding never blocks you.

Scope

Emit-only, by design. Parsing AsyncAPI documents and generating code from them is well served by lerenn/asyncapi-codegen and bdragon300/go-asyncapi; this library does not duplicate them. Go structs stay the source of truth and the document is the description of them.

Comparison

Library Direction AsyncAPI version Mechanism
asyncapi3 (this) code → spec 3.0.0 Go values + struct reflection
swaggest/go-asyncapi code → spec up to 2.4.0 struct reflection
asyncapi-go/asyncapigo code → spec 2.4.0 source annotations
lerenn/asyncapi-codegen spec → code 2.6, 3.0 app/broker code generation
bdragon300/go-asyncapi spec → code 3.0 code generation + tooling

Versions as observed in July 2026; check upstream before relying on this table.

Status

v0.x — the API may still change. The document model is a curated subset of the 3.0.0 specification covering what real services need first: servers, channels with address parameters, send/receive operations with request/reply, messages, components, and raw bindings. It is used in production to describe a third-party-embedded WebSocket contract and an internal SPA streaming contract.

v1.0 waits on: the API surviving at least one external adopter and a full minor cycle without breaking changes, and first-class binding types for ws, http, amqp, kafka, and mqtt (today those attach as raw JSON).

Issues and pull requests welcome — see CONTRIBUTING.md.

License

Apache-2.0

Documentation

Overview

Package asyncapi3 emits AsyncAPI 3.0.0 documents from Go code.

Marshaled output is deterministic (maps sort, struct order is fixed), so regenerating an unchanged document is byte-identical — a contract relied on by regen-diff CI gates.

Index

Constants

View Source
const (
	ActionSend    = "send"
	ActionReceive = "receive"
)
View Source
const Version = "3.0.0"

Variables

This section is empty.

Functions

func Check

func Check(generated []byte, path string) error

Check compares freshly generated document bytes against the committed artifact at path, so contract-drift gating runs as one tested code path locally and in CI instead of shell logic in a workflow.

func MergeSchemas

func MergeSchemas(dst, src map[string]json.RawMessage) error

MergeSchemas folds src into dst, failing on same-name definitions with different content — a silent overwrite would corrupt one of the schemas.

func SchemaFromType

func SchemaFromType(v any, opts ...ReflectOption) (json.RawMessage, map[string]json.RawMessage, error)

func ValidateBytes

func ValidateBytes(document []byte) error

ValidateBytes checks an already-marshalled AsyncAPI document against the embedded official AsyncAPI 3.0.0 meta-schema.

Types

type Channel

type Channel struct {
	Address     string               `json:"address,omitempty"`
	Title       string               `json:"title,omitempty"`
	Summary     string               `json:"summary,omitempty"`
	Description string               `json:"description,omitempty"`
	Messages    map[string]Message   `json:"messages,omitempty"`
	Parameters  map[string]Parameter `json:"parameters,omitempty"`
	Servers     []RefObj             `json:"servers,omitempty"`
	Tags        []Tag                `json:"tags,omitempty"`
	Bindings    json.RawMessage      `json:"bindings,omitempty"`
}

type Components

type Components struct {
	Schemas    map[string]json.RawMessage `json:"schemas,omitempty"`
	Messages   map[string]Message         `json:"messages,omitempty"`
	Parameters map[string]Parameter       `json:"parameters,omitempty"`
	Servers    map[string]Server          `json:"servers,omitempty"`
	Channels   map[string]Channel         `json:"channels,omitempty"`
}

type Contact

type Contact struct {
	Name  string `json:"name,omitempty"`
	URL   string `json:"url,omitempty"`
	Email string `json:"email,omitempty"`
}

type Document

type Document struct {
	AsyncAPI           string               `json:"asyncapi"`
	ID                 string               `json:"id,omitempty"`
	Info               Info                 `json:"info"`
	DefaultContentType string               `json:"defaultContentType,omitempty"`
	Servers            map[string]Server    `json:"servers,omitempty"`
	Channels           map[string]Channel   `json:"channels,omitempty"`
	Operations         map[string]Operation `json:"operations,omitempty"`
	Components         *Components          `json:"components,omitempty"`
}

func New

func New(title, version string) *Document

func (*Document) Validate

func (d *Document) Validate() error

Validate checks the marshalled document against the official AsyncAPI 3.0.0 meta-schema, which is embedded — validation never reaches the network.

type ExternalDocs

type ExternalDocs struct {
	Description string `json:"description,omitempty"`
	URL         string `json:"url"`
}

type Info

type Info struct {
	Title          string        `json:"title"`
	Version        string        `json:"version"`
	Description    string        `json:"description,omitempty"`
	TermsOfService string        `json:"termsOfService,omitempty"`
	Contact        *Contact      `json:"contact,omitempty"`
	License        *License      `json:"license,omitempty"`
	Tags           []Tag         `json:"tags,omitempty"`
	ExternalDocs   *ExternalDocs `json:"externalDocs,omitempty"`
}

type License

type License struct {
	Name string `json:"name"`
	URL  string `json:"url,omitempty"`
}

type Message

type Message struct {
	Ref         string          `json:"$ref,omitempty"`
	Name        string          `json:"name,omitempty"`
	Title       string          `json:"title,omitempty"`
	Summary     string          `json:"summary,omitempty"`
	Description string          `json:"description,omitempty"`
	ContentType string          `json:"contentType,omitempty"`
	Headers     json.RawMessage `json:"headers,omitempty"`
	Payload     json.RawMessage `json:"payload,omitempty"`
	Examples    json.RawMessage `json:"examples,omitempty"`
	Tags        []Tag           `json:"tags,omitempty"`
	Bindings    json.RawMessage `json:"bindings,omitempty"`
}

type Operation

type Operation struct {
	Action      string          `json:"action,omitempty"`
	Channel     RefObj          `json:"channel,omitzero"`
	Title       string          `json:"title,omitempty"`
	Summary     string          `json:"summary,omitempty"`
	Description string          `json:"description,omitempty"`
	Messages    []RefObj        `json:"messages,omitempty"`
	Reply       *OperationReply `json:"reply,omitempty"`
	Tags        []Tag           `json:"tags,omitempty"`
	Bindings    json.RawMessage `json:"bindings,omitempty"`
}

type OperationReply

type OperationReply struct {
	Channel  RefObj   `json:"channel,omitzero"`
	Messages []RefObj `json:"messages,omitempty"`
}

type Parameter

type Parameter struct {
	Description string   `json:"description,omitempty"`
	Enum        []string `json:"enum,omitempty"`
	Default     string   `json:"default,omitempty"`
	Examples    []string `json:"examples,omitempty"`
	Location    string   `json:"location,omitempty"`
}

type RefObj

type RefObj struct {
	Ref string `json:"$ref,omitempty"`
}

func Ref

func Ref(target string) RefObj

type ReflectOption

type ReflectOption func(*reflectConfig)

func RequireAll

func RequireAll() ReflectOption

RequireAll marks every property of every reflected definition as required. Correct only for payloads whose Go structs never use omitempty — Go then marshals every field on every message.

type Server

type Server struct {
	Host        string          `json:"host"`
	Protocol    string          `json:"protocol"`
	Pathname    string          `json:"pathname,omitempty"`
	Description string          `json:"description,omitempty"`
	Title       string          `json:"title,omitempty"`
	Summary     string          `json:"summary,omitempty"`
	Tags        []Tag           `json:"tags,omitempty"`
	Bindings    json.RawMessage `json:"bindings,omitempty"`
}

type Tag

type Tag struct {
	Name        string `json:"name"`
	Description string `json:"description,omitempty"`
}

Directories

Path Synopsis
examples
requestreply command
Command requestreply emits an AsyncAPI 3.0 document for an in-band authentication handshake: the server asks for a token, the client answers on the same channel.
Command requestreply emits an AsyncAPI 3.0 document for an in-band authentication handshake: the server asks for a token, the client answers on the same channel.
websocket command
Command websocket emits an AsyncAPI 3.0 document for a server-to-client WebSocket broadcast, with the payload schema reflected from the Go struct that is actually written to the socket.
Command websocket emits an AsyncAPI 3.0 document for a server-to-client WebSocket broadcast, with the payload schema reflected from the Go struct that is actually written to the socket.

Jump to

Keyboard shortcuts

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