asyncapi3

package module
v0.2.0 Latest Latest
Warning

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

Go to latest
Published: Jul 29, 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.

Declare servers, channels, and operations as Go values, reflect payload schemas from the structs that cross the wire with SchemaFromType, and marshal the Document to JSON or YAML.

Marshalled output is deterministic — maps marshal key-sorted and struct field order is fixed — so regenerating an unchanged document is byte-identical. That property is what makes a committed document gateable in CI; see Check.

The document model is a curated subset of the specification. Spec objects and protocol bindings it does not model yet attach as raw JSON through the Bindings fields, so an unmodelled binding never blocks you.

Index

Constants

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

Operation actions, as defined by the specification: an application either sends a message to a channel or receives one from it. Both are expressed from the point of view of the application described by the document.

View Source
const Version = "3.0.0"

Version is the AsyncAPI specification version this package emits.

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)

SchemaFromType reflects v into a JSON Schema, returning the payload schema for the value itself — a "$ref" into "#/components/schemas/" — and the definitions it references, ready to assign to Components.Schemas.

Property names come from json struct tags. Schema keywords are read from the tags jsonschema-go understands, including required:"true", so the wire contract is declared on the struct rather than restated here.

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"`
}

Channel is an addressable path messages flow through. An Address may embed parameters in braces — "/ports/{unlocode}" — each of which must have a matching entry in Parameters.

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"`
}

Components holds reusable definitions referenced from elsewhere in the document. Schemas is where SchemaFromType definitions belong; entries are referenced as "#/components/schemas/Name".

type Contact

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

Contact identifies who to reach about the API.

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"`
}

Document is the root of an AsyncAPI document. Build one with New so the specification version is set correctly.

func New

func New(title, version string) *Document

New returns a Document for the current specification version with its required info fields populated.

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"`
}

ExternalDocs points at documentation held outside the document.

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"`
}

Info carries metadata about the API. Title and Version are required by the specification.

type License

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

License names the license the API is published under.

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"`
}

Message describes one kind of message on a channel. Set Ref alone to reference a message defined under Components; otherwise Payload carries the schema, typically produced by SchemaFromType.

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"`
}

Operation is an action the application performs on a channel: ActionSend or ActionReceive. Set Reply to describe a request/reply exchange.

type OperationReply

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

OperationReply describes the response half of a request/reply exchange, and the channel it arrives on — which may be the request channel itself.

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"`
}

Parameter describes one substitution in a channel address.

type RefObj

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

RefObj is a JSON Reference to another part of the document. Build one with Ref.

func Ref

func Ref(target string) RefObj

Ref returns a reference to target, e.g. "#/channels/portTotals".

type ReflectOption

type ReflectOption func(*reflectConfig)

ReflectOption configures SchemaFromType.

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"`
}

Server describes where the API is reachable. Host and Protocol are required by the specification; Bindings carries protocol-specific configuration as raw JSON.

type Tag

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

Tag groups channels, operations, or messages under a common label.

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