Reference

AsyncAPI Module

Auto-generated AsyncAPI 2.6 spec served with interactive AsyncAPI Studio UI.

Module: github.com/redelay/go-framework/modules/asyncapi

The asyncapi module auto-generates an AsyncAPI 2.6 specification from all registered module events and consumers, then serves it as YAML alongside an interactive AsyncAPI Studio UI — the event equivalent of Scalar/Swagger UI for REST.

Quick start

go
import (
    _ "github.com/redelay/go-framework/modules/asyncapi"
)

That's it. The module is auto-discovered at bootstrap. Your service will serve:

PathDescription
/asyncapi.jsonAsyncAPI 2.6 spec, JSON (Content-Type: application/json)
/asyncapi.yamlAsyncAPI 2.6 spec, YAML (Content-Type: application/yaml)
/asyncapiAsyncAPI Studio — interactive event browser

All three mount at the root, outside ROUTE_PREFIX, and are advertised in /openapi.json at those absolute paths (via DynamicRoutesProvider with AbsolutePath). The single spec handler content-negotiates by path suffix — .json → JSON, anything else → YAML — so /asyncapi.json and /asyncapi.yaml share one handler. Configure the paths with ASYNCAPI_SPEC_PATH, ASYNCAPI_YAML_PATH, and ASYNCAPI_UI_PATH.

How the spec is generated

The module walks every registered module at startup (lazily, on first request) and collects:

  1. Events from EventsProvider.Events() → AsyncAPI channels (one channel per topic)
  2. Consumers from EventsProvider.Consumers() → subscribe-side operations with groupId Kafka bindings
  3. Packet schemas from ir.Event.Payload → components/schemas
text
Module 1: Events() → [user.created, user.deleted]
Module 2: Events() → [email.send]
Module 2: Consumers() → [user.created group=email-sender]

          ↓ asyncapi.Export()

channels:
  user.created:
    publish:
      operationId: user.created
      message: { $ref: '#/components/messages/UserCreated' }
  email.send:
    publish:
      operationId: email.send
  user.created:
    subscribe:
      operationId: consume_user.created
      bindings:
        kafka:
          groupId: email-sender

If a module's ir.Event has no explicit Topic, the channel key defaults to entity_type.action.

Declaring events for the spec

Implement EventsProvider on your module. The Events() return value is both the runtime contract (used by go-events for routing) and the source of truth for the AsyncAPI spec:

go
func (m *Module) Events() []*ir.Event {
    return []*ir.Event{
        {
            Name:        "order.created",
            EntityType:  "order",
            Action:      "created",
            Topic:       "order.created",
            Description: "Fired when a new order is placed.",
            Payload: &ir.Packet{
                ID:   "OrderCreatedPayload",
                Name: "OrderCreatedPayload",
                Fields: []*ir.Field{
                    {Name: "order_id",  Type: ir.FieldTypeUUID,   Required: true},
                    {Name: "total",     Type: ir.FieldTypeFloat,  Required: true},
                    {Name: "currency",  Type: ir.FieldTypeString, Required: true},
                },
            },
        },
    }
}

func (m *Module) Consumers() []*modules.ConsumerRegistration {
    return []*modules.ConsumerRegistration{
        {
            EventName: "payment.completed",
            Topic:     "payment.completed",
            GroupID:   "orders",
            Handler:   m.handlePaymentCompleted,
        },
    }
}

The Payload field is optional — if omitted, the message schema is left open. Adding it produces a components/schemas entry and a $ref in the channel's message definition.

Example AsyncAPI output

For a service with auth and users modules, the generated spec looks like:

yaml
asyncapi: "2.6.0"
info:
  title: My Service
  version: "1.0.0"
channels:
  auth.login:
    description: Successful authentication
    publish:
      operationId: auth.login
      summary: Successful authentication
      message:
        name: auth.login
        contentType: application/json
  users.user_created:
    description: New user registered
    publish:
      operationId: users.user_created
      message:
        name: users.user_created
        contentType: application/json
        payload:
          $ref: '#/components/schemas/UserCreatedPayload'
components:
  schemas:
    UserCreatedPayload:
      type: object
      properties:
        user_id:  { type: string }
        email:    { type: string }
      required: [user_id, email]

AsyncAPI Studio UI

The /asyncapi endpoint serves a self-contained HTML page powered by @asyncapi/react-component 3.x (standalone CDN build). No Node.js or build step required.

The Studio renders:

  • Sidebar — channel list with publish/subscribe badges
  • Info panel — title, version, description
  • Operations — one per event with message schema
  • Schemas — components/schemas browser

To disable the UI (spec-only mode):

shell
ASYNCAPI_UI=disabled

Referencing the spec from FlowDSL

Services using FlowDSL can declare packet schemas by reference to the live AsyncAPI spec, ensuring event contracts stay in sync across services:

yaml
# In a .flowdsl.yaml file
packets:
  - id: order_created_payload
    $ref: "https://api.example.com/asyncapi.json#/components/schemas/OrderCreatedPayload"

See FlowDSL Integration for the full pattern.

Cross-language schema validation

Both Go and Python services can load the spec at startup and validate every incoming event payload against it:

Go (via go-events/schema):

go
// Automatically loaded when ASYNCAPI_URL env var is set.
// ASYNCAPI_URL=http://api-service/asyncapi.json

// Manual:
import "github.com/redelay/go-events/schema"

reg, err := schema.LoadFromURL("http://api-service/asyncapi.json")
err = reg.Validate("order.created", payloadBytes)

Python (coming soon):

python
# Set at startup — py-events loads and caches the schema.
ASYNCAPI_URL=http://api-service/asyncapi.json

Modspec integration

The /modules browser (modspec) links directly to /asyncapi and /reference from its top navigation bar. Each module card shows an Events tab and a Consumers tab alongside the diagram and YAML views.

Configuration

VariableDefaultDescription
ASYNCAPI_UIstudioUI provider (studio or disabled)
ASYNCAPI_SPEC_PATH/asyncapi.jsonURL path for the YAML spec
ASYNCAPI_UI_PATH/asyncapiURL path for the Studio UI
APP_NAMEredelayService name in the spec info.title
APP_VERSION1.0.0Version string in the spec info.version

Programmatic spec generation

The underlying core/asyncapi package can generate or parse AsyncAPI specs directly, independent of the HTTP module:

go
import "github.com/redelay/go-framework/core/asyncapi"

// Export IR to AsyncAPI YAML
err := asyncapi.Export(doc, writer)

// Import AsyncAPI YAML into IR
doc, err := asyncapi.Import(reader)

See Core IR & Compilation for full details on the compile pipeline.