Documentation
¶
Overview ¶
Package events provides a transport-agnostic event channel builder for go-codex.
Define channels declaratively with codec-backed payload types; register them with a Builder to obtain a ChannelHandle with typed Decode and Encode helpers. Pass those helpers to any message broker (MQTT, AMQP, Kafka, NATS) — this package does not import any messaging library.
Spec generation is also available: Builder.AsyncAPISpec derives a complete AsyncAPI 3.0 document from the registered channels.
Typical usage:
b := events.NewBuilder(events.Info{Title: "User Events", Version: "1.0.0"})
b.AddServer("production", events.Server{
URL: "mqtt://broker.example.com",
Protocol: "mqtt",
})
// Declare the channel as a value — define once, pass around, register later.
var userCreated = events.NewChannel[UserCreated]("user/created", userCreatedCodec,
events.ChannelMeta{Description: "A user was created"},
events.Subscribe{Summary: "Receive user created events", SchemaName: "UserCreatedEvent"},
)
handle, err := userCreated.Register(b)
// In your broker callback (any library):
event, err := handle.Decode(msg.Payload()) // JSON → UserCreated, validates
payload, err := handle.Encode(event) // UserCreated → JSON
// AsyncAPI 3.0 spec:
doc, err := b.AsyncAPISpec()
yaml, _ := doc.MarshalYAML()
Encoding is JSON only by default. For other formats construct a format.Format directly and pass it to the adapter (e.g. adapters/mqtt.SubscribeHandler).
Index ¶
- type Builder
- func (b *Builder) AddGlobalSecurity(reqs ...route.SecurityRequirement) *Builder
- func (b *Builder) AddSchema(name string, s schema.Schema) *Builder
- func (b *Builder) AddSecurityScheme(name string, s SecurityScheme) *Builder
- func (b *Builder) AddServer(name string, s Server) *Builder
- func (b *Builder) AppendTo(db *asyncapi.DocumentBuilder) error
- func (b *Builder) AsyncAPISpec() (asyncapi.Document, error)
- type BuilderOption
- type Channel
- type ChannelHandle
- func (h *ChannelHandle[T]) BuildTopic(vars map[string]string) (string, error)
- func (h *ChannelHandle[T]) ValidateTopic(topic string) error
- func (h *ChannelHandle[T]) ValidateTopicVars(vars map[string]string) error
- func (h *ChannelHandle[T]) WithFormats(fmts ...format.Format[T]) *ChannelHandle[T]
- func (h *ChannelHandle[T]) WithPublishFormats(fmts ...format.Format[T]) *ChannelHandle[T]
- func (h *ChannelHandle[T]) WithSubscribeFormats(fmts ...format.Format[T]) *ChannelHandle[T]
- type ChannelMeta
- type ChannelOpt
- type Info
- type InvalidTopicError
- type InvalidTopicParamError
- type MissingTopicVarError
- type Publish
- type SecurityScheme
- type Server
- type Subscribe
- type TopicParam
- type TopicParamError
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Builder ¶
type Builder struct {
// contains filtered or unexported fields
}
Builder accumulates channel registrations and produces AsyncAPI specs. Create one with NewBuilder.
func NewBuilder ¶
func NewBuilder(info Info, opts ...BuilderOption) *Builder
NewBuilder returns a Builder initialised with the given API metadata.
func (*Builder) AddGlobalSecurity ¶ added in v0.8.0
func (b *Builder) AddGlobalSecurity(reqs ...route.SecurityRequirement) *Builder
AddGlobalSecurity appends security requirements that apply to all channels by default. The requirements flow into runtime enforcement: channels with nil Subscribe.Security or Publish.Security inherit these requirements at the adapter layer via ChannelHandle.GlobalSecurity.
AsyncAPI 3.0 has no document-level global security field; these requirements do NOT appear in the AsyncAPI spec output. To annotate per-channel security in the spec, set Subscribe.Security or Publish.Security explicitly.
To mark a specific channel as explicitly unsecured (exempt from global security), set Security to an empty slice: Security: []route.SecurityRequirement{}.
func (*Builder) AddSchema ¶
AddSchema registers a named schema in components/schemas. Use this to register reusable schemas that are referenced by SchemaName in channel configs but not inlined in any codec.
func (*Builder) AddSecurityScheme ¶ added in v0.8.0
func (b *Builder) AddSecurityScheme(name string, s SecurityScheme) *Builder
AddSecurityScheme registers a named security scheme with the builder. The spec fields flow into the AsyncAPI document via AsyncAPISpec; Codec, when non-nil, is used by adapters to validate extracted credentials before SecurityFunc is called (MQTT adapters skip Codec validation — use SecurityFunc).
The name must match those used in route.Require calls on Subscribe/Publish Security fields and in Builder.AddGlobalSecurity.
func (*Builder) AddServer ¶
AddServer registers a named server entry in the spec. Servers appear in the AsyncAPI output in registration order. If s.Description is empty, name is used as the description.
func (*Builder) AppendTo ¶ added in v0.11.0
func (b *Builder) AppendTo(db *asyncapi.DocumentBuilder) error
AppendTo writes all channels registered on this Builder into db, which must have been created by asyncapi.NewDocumentBuilder. Servers, schemas, and security schemes owned by this Builder are NOT written — the caller is responsible for configuring those on db.
Use AppendTo to combine pub/sub channels with request-reply channels from api/reqreply.Builder in a single AsyncAPI 3.0 document:
import asyncapi "github.com/DaniDeer/go-codex/render/asyncapi/v3"
doc := asyncapi.NewDocumentBuilder(info)
doc.AddServer("mqtt5", asyncapi.Server{URL: "mqtts://...", Protocol: "mqtt5"})
eventsB.AppendTo(doc) // pub/sub channels
reqreplyB.AppendTo(doc) // request-reply channels
spec, err := doc.Build()
func (*Builder) AsyncAPISpec ¶
AsyncAPISpec builds a complete AsyncAPI 3.0 document from all registered channels. Returns an error if any non-empty SchemaName references a schema that will not be present in components/schemas (a dangling $ref).
type BuilderOption ¶ added in v0.4.0
type BuilderOption func(*Builder)
BuilderOption configures a Builder at construction time.
func WithTopicCodec ¶ added in v0.4.0
func WithTopicCodec(c codex.Codec[string]) BuilderOption
WithTopicCodec sets a codec used to validate every topic passed to Channel.Register. If the topic is invalid, Channel.Register returns an error immediately.
Use WithTopicConstraints for the common case of stacking one or more codex.Constraint values; use WithTopicCodec when you need a fully-custom codex.Codec.
Example — enforce MQTT publish topic rules:
import "github.com/DaniDeer/go-codex/validate" b := events.NewBuilder(info, events.WithTopicConstraints(validate.MQTTPublishTopic))
func WithTopicConstraints ¶ added in v0.4.0
func WithTopicConstraints(cons ...codex.Constraint[string]) BuilderOption
WithTopicConstraints is a convenience wrapper around WithTopicCodec that builds a codec from codex.String refined with the given constraints. Multiple constraints are applied in order; all must pass.
Users can mix built-in constraints from the validate package with their own:
sensorLevel := codex.Constraint[string]{
Name: "sensor-prefix",
Check: func(v string) bool { return strings.HasPrefix(v, "sensors/") },
Message: func(v string) string { return fmt.Sprintf("topic must start with sensors/, got %q", v) },
}
b := events.NewBuilder(info, events.WithTopicConstraints(validate.MQTTPublishTopic, sensorLevel))
type Channel ¶ added in v0.8.0
type Channel[T any] struct { // contains filtered or unexported fields }
Channel is a declarative event channel spec: topic, codec, and options. It is a value type — define it once, store it, pass it around, and register it with one or more Builder instances via Channel.Register.
Create a Channel with NewChannel.
func NewChannel ¶ added in v0.8.0
NewChannel creates a Channel spec from a topic, codec, and variadic opts. NewChannel is infallible — it only captures the spec. Validation (topic codec, TopicParam template consistency) runs at Channel.Register time.
Pass any combination of ChannelMeta, Subscribe, Publish, and TopicParam as opts. All opts are optional.
NewChannel is a free function (not a method) because Go requires type parameters to appear on free functions, not on method receivers.
Typical usage:
var userCreated = events.NewChannel[UserCreated]("user/created", userCreatedCodec,
events.ChannelMeta{Description: "A user was created"},
events.Subscribe{Summary: "Receive user created events", SchemaName: "UserCreatedEvent"},
)
// Later, register with a builder:
handle, err := userCreated.Register(b)
Example ¶
package main
import (
"fmt"
"github.com/DaniDeer/go-codex/api/events"
"github.com/DaniDeer/go-codex/codex"
)
func main() {
type SensorReading struct {
SensorID string
Value float64
}
readingCodec := codex.Struct[SensorReading](
codex.RequiredField("sensor_id", codex.String(),
func(r SensorReading) string { return r.SensorID },
func(r *SensorReading, v string) { r.SensorID = v },
),
codex.RequiredField("value", codex.Float64(),
func(r SensorReading) float64 { return r.Value },
func(r *SensorReading, v float64) { r.Value = v },
),
)
b := events.NewBuilder(events.Info{Title: "Sensor API", Version: "1.0.0"})
// NewChannel declares a typed channel as a value — register with any builder.
ch := events.NewChannel[SensorReading](
"sensors/{sensorID}/readings",
readingCodec,
events.Subscribe{OperationID: "receiveSensorReading", Summary: "Receive a reading"},
)
handle, err := ch.Register(b)
if err != nil {
fmt.Println("register error:", err)
return
}
// Decode a payload.
reading, err := handle.Decode([]byte(`{"sensor_id":"s1","value":42.5}`))
if err != nil {
fmt.Println("decode error:", err)
return
}
fmt.Printf("sensor=%s value=%.1f\n", reading.SensorID, reading.Value)
}
Output: sensor=s1 value=42.5
func (Channel[T]) ClientHandle ¶ added in v0.11.0
func (c Channel[T]) ClientHandle() *ChannelHandle[T]
ClientHandle returns a ChannelHandle for client-side use without registering with a Builder. No spec registration occurs (SecuritySchemes and GlobalSecurity are left empty).
Use ClientHandle when only the codec and topic definitions are needed (no AsyncAPI spec, no server), or when sharing a Channel definition between publisher and subscriber in the same binary without a builder registration.
The returned handle has the same Decode / Encode helpers and BuildTopic / ValidateTopicVars methods as a handle returned by Channel.Register.
Example — client-only usage (no builder required):
var SensorChannel = events.NewChannel[SensorReading]("sensors/{sensorID}/data",
sensorCodec, events.TopicParam{Name: "sensorID"}.WithCodec(sensorIDCodec),
)
handle := SensorChannel.ClientHandle()
domain.SensorReadings.Bind(ctx, mqtt5.SubscribeAdapter(client, router, handle, 0, fmt, opts))
Mirrors [rest.Route.ClientHandle] and [reqreply.Route.ClientHandle].
func (Channel[T]) Register ¶ added in v0.8.0
func (c Channel[T]) Register(b *Builder) (*ChannelHandle[T], error)
Register registers the channel with b and returns a ChannelHandle.
If the builder was created with WithTopicCodec or WithTopicConstraints, the topic is validated immediately and an error is returned if it fails — no channel is registered in that case.
Any TopicParam entry whose name does not appear as a {varName} placeholder in the topic template causes Register to return an error immediately.
type ChannelHandle ¶
type ChannelHandle[T any] struct { // Topic is the channel name (e.g. "user/created", "orders.placed"). Topic string // Descriptor is the live asyncapi.ChannelItem descriptor. It reflects the // current configuration and is used by the builder at AsyncAPISpec() time. Descriptor asyncapi.ChannelItem // Decode deserialises and validates a JSON payload into T. // All Refine constraints on the payload codec run automatically. Decode func(payload []byte) (T, error) // Encode serialises T to JSON bytes. Encode func(msg T) ([]byte, error) // Formats, when non-empty, specifies the default payload format for both // subscribe (decode) and publish (encode). The adapter uses Formats[0] when // no call-time format override is provided. Defaults to JSON when empty. // Configure via [ChannelHandle.WithFormats]. // Use [ChannelHandle.WithSubscribeFormats] / [ChannelHandle.WithPublishFormats] // for asymmetric channels where decode and encode use different formats. Formats []format.Format[T] // SubscribeFormats, when non-empty, overrides Formats for the subscribe // (receive / decode) direction only. The adapter uses SubscribeFormats[0] // instead of Formats[0] when decoding incoming messages. // Configure via [ChannelHandle.WithSubscribeFormats]. SubscribeFormats []format.Format[T] // PublishFormats, when non-empty, overrides Formats for the publish // (send / encode) direction only. The adapter uses PublishFormats[0] // instead of Formats[0] when encoding outgoing messages. // Configure via [ChannelHandle.WithPublishFormats]. PublishFormats []format.Format[T] // SecuritySchemes maps scheme name to SecurityScheme (with runtime Codec). // Populated from Builder.AddSecurityScheme when AddChannel is called. // Adapters use this map to extract and validate credentials per scheme. SecuritySchemes map[string]SecurityScheme // GlobalSecurity holds the builder-level security requirements that apply // when the channel operation's Security field is nil (i.e. the channel // inherits global security). Adapters resolve the effective requirements as: // reqs := handle.Descriptor.Subscribe.Security // if reqs == nil { reqs = handle.GlobalSecurity } // Set via [Builder.AddGlobalSecurity]. nil when no global security is declared. GlobalSecurity []route.SecurityRequirement // contains filtered or unexported fields }
ChannelHandle is returned by Channel.Register. It holds the spec descriptor and codec-backed Decode/Encode helpers.
func (*ChannelHandle[T]) BuildTopic ¶ added in v0.4.0
func (h *ChannelHandle[T]) BuildTopic(vars map[string]string) (string, error)
BuildTopic substitutes {varName} placeholders in the channel's topic template with the values provided in vars, validating each against its registered codec (if any).
All template variables must be present in vars; missing variables return an error. Values are validated before substitution; codec failures return a TopicParamError that identifies the variable name and the failing value. Keys in vars that do not appear in the template are silently ignored.
If the builder was created with WithTopicCodec or WithTopicConstraints, the final assembled topic is also validated against that codec. A failure returns an InvalidTopicError with the concrete topic (not the template).
Example:
topic, err := sensorChannel.BuildTopic(map[string]string{"sensorID": "f47ac10b-..."})
// topic = "sensors/f47ac10b-.../measurements"
func (*ChannelHandle[T]) ValidateTopic ¶ added in v0.8.0
func (h *ChannelHandle[T]) ValidateTopic(topic string) error
ValidateTopic validates a received concrete topic string against the builder-level topic codec (set via WithTopicCodec or WithTopicConstraints).
Call this after a wildcard subscription delivers a message to verify the concrete topic satisfies the same constraints applied at channel registration time. Returns InvalidTopicError on failure; returns nil if no topic codec is registered.
Note: unlike Channel.Register, which validates a template-stripped topic, this method validates the concrete topic as-is (with real segment values in place).
func (*ChannelHandle[T]) ValidateTopicVars ¶ added in v0.8.0
func (h *ChannelHandle[T]) ValidateTopicVars(vars map[string]string) error
ValidateTopicVars validates extracted topic variable values against the registered TopicParam codecs. Call this after [TopicVarsFromMessage] has extracted the vars map to ensure each variable satisfies its codec constraints.
Returns TopicParamError for the first variable that fails its codec. Variables without a registered codec are skipped.
func (*ChannelHandle[T]) WithFormats ¶ added in v0.8.0
func (h *ChannelHandle[T]) WithFormats(fmts ...format.Format[T]) *ChannelHandle[T]
WithFormats sets the default payload format for this channel. The adapter uses Formats[0] for both subscribe (decode) and publish (encode) when no call-time format override is provided. Defaults to JSON when empty.
WithFormats also updates the live AsyncAPI descriptor: if fmts is non-empty, Message.ContentType on each registered operation (Subscribe/Publish) is set to fmts[0].ContentType(). Calling WithFormats with no arguments clears both Formats and the content-type override (restoring the AsyncAPI default).
This mirrors [rest.RouteHandle.WithFormats] for event channels. Call it after Channel.Register to configure non-JSON payload serialisation:
ch = ch.WithFormats(format.YAML(measurementCodec)) // Adapter uses YAML automatically — no format arg needed: client.Subscribe(topic, 1, amqtt.SubscribeHandler(ctx, ch, fn, opts))
func (*ChannelHandle[T]) WithPublishFormats ¶ added in v0.8.0
func (h *ChannelHandle[T]) WithPublishFormats(fmts ...format.Format[T]) *ChannelHandle[T]
WithPublishFormats sets the default payload format for the publish (send / encode) direction only, leaving the subscribe direction unchanged. The adapter uses PublishFormats[0] when encoding outgoing messages. Calling with no arguments clears the publish-specific override (Formats is used).
Use this for asymmetric channels where inbound and outbound payloads use different serialisation formats (e.g. YAML in, JSON out).
func (*ChannelHandle[T]) WithSubscribeFormats ¶ added in v0.8.0
func (h *ChannelHandle[T]) WithSubscribeFormats(fmts ...format.Format[T]) *ChannelHandle[T]
WithSubscribeFormats sets the default payload format for the subscribe (receive / decode) direction only, leaving the publish direction unchanged. The adapter uses SubscribeFormats[0] when decoding incoming messages. Calling with no arguments clears the subscribe-specific override (Formats is used).
Use this for asymmetric channels where inbound and outbound payloads use different serialisation formats (e.g. YAML in, JSON out).
type ChannelMeta ¶ added in v0.8.0
ChannelMeta holds channel-level metadata for a channel registration: title, summary, description, and tags. All fields are optional. The values flow into the generated AsyncAPI ChannelItem.
ChannelMeta implements ChannelOpt: pass it directly to NewChannel.
type ChannelOpt ¶ added in v0.8.0
type ChannelOpt interface {
// contains filtered or unexported methods
}
ChannelOpt is the sealed interface for variadic NewChannel options.
The following types implement ChannelOpt:
- ChannelMeta — channel-level metadata (title, summary, description, tags)
- Subscribe — subscribe operation metadata (application receives messages)
- Publish — publish operation metadata (application sends messages)
- TopicParam — topic template variable with optional codec and description
type Info ¶
Info is an alias for asyncapi.Info. Using the alias avoids duplicating fields and keeps the two in sync automatically.
type InvalidTopicError ¶ added in v0.4.0
type InvalidTopicError struct {
Topic string // the topic that failed validation
Err error // the underlying constraint or codec error
}
InvalidTopicError is returned by Channel.Register when the topic fails builder-level topic codec validation.
Use errors.As to extract it and inspect the failing topic or the underlying constraint error:
var topicErr events.InvalidTopicError
if errors.As(err, &topicErr) {
log.Printf("bad topic %q: %v", topicErr.Topic, topicErr.Err)
}
func (InvalidTopicError) Error ¶ added in v0.4.0
func (e InvalidTopicError) Error() string
func (InvalidTopicError) Unwrap ¶ added in v0.4.0
func (e InvalidTopicError) Unwrap() error
Unwrap allows errors.As and errors.Is to traverse the underlying constraint error.
type InvalidTopicParamError ¶ added in v0.6.0
type InvalidTopicParamError struct {
Name string // the variable name (without braces) that is not in the template
Topic string // the topic template that was validated against
}
InvalidTopicParamError is returned by Channel.Register when a TopicParam entry names a variable that does not appear in the topic template.
Use errors.As to extract the offending name and the topic template:
var paramErr events.InvalidTopicParamError
if errors.As(err, ¶mErr) {
log.Printf("TopicParam %q not in topic %q", paramErr.Name, paramErr.Topic)
}
func (InvalidTopicParamError) Error ¶ added in v0.6.0
func (e InvalidTopicParamError) Error() string
type MissingTopicVarError ¶ added in v0.4.0
type MissingTopicVarError struct {
Name string // the variable name (without braces) that had no value
}
MissingTopicVarError is returned by ChannelHandle.BuildTopic when a {varName} placeholder in the topic template has no corresponding entry in the vars map.
Use errors.As to extract the missing variable name:
var missingErr events.MissingTopicVarError
if errors.As(err, &missingErr) {
log.Printf("caller forgot to supply topic variable {%s}", missingErr.Name)
}
func (MissingTopicVarError) Error ¶ added in v0.4.0
func (e MissingTopicVarError) Error() string
type Publish ¶ added in v0.8.0
type Publish struct {
// OperationID is the unique identifier for the publish operation in the
// AsyncAPI spec. Used by code generators and documentation tools.
OperationID string
Summary string
Description string
Tags []string
// SchemaName, when non-empty, emits a $ref for the payload schema in the
// spec and registers the schema under that name in components/schemas.
SchemaName string
// Security, when non-nil, overrides global security for this operation.
// Pass an empty slice to declare "no auth required" for this publish operation.
// nil (default) inherits global security declared via [Builder.AddGlobalSecurity].
Security []route.SecurityRequirement
}
Publish describes the publish operation on a channel (application sends). It controls the publish entry in the AsyncAPI spec.
Publish implements ChannelOpt: pass it directly to NewChannel.
type SecurityScheme ¶ added in v0.8.0
type SecurityScheme struct {
route.SecurityScheme
// Codec, when non-nil, validates the extracted raw credential string.
// Nil means no format validation; SecurityFunc receives the message as-is.
Codec *codex.Codec[string]
}
SecurityScheme combines route.SecurityScheme spec metadata with optional runtime credential validation for message broker adapters.
AddSecurityScheme registers it with the builder. The spec fields flow into the AsyncAPI document; Codec, when non-nil, is used by adapters to validate the raw credential string before SecurityFunc is called.
MQTT note: paho.mqtt.golang (MQTT 3.1.1) does not expose per-message credentials. Codec-level extraction is a no-op for standard MQTT. Use SecurityFunc + closure (credentials passed at MQTT CONNECT time) for runtime enforcement.
Use SecurityScheme.WithCodec to set the Codec field inline without a temporary variable: events.SecurityScheme{SecurityScheme: route.APIKeyScheme(...)}.WithCodec(c)
func (SecurityScheme) WithCodec ¶ added in v0.8.0
func (s SecurityScheme) WithCodec(c codex.Codec[string]) SecurityScheme
WithCodec returns a copy of s with Codec set to c. It avoids the temporary-variable + address-of pattern required when setting Codec inline:
b.AddSecurityScheme("apiKey", events.SecurityScheme{
SecurityScheme: route.APIKeyScheme("X-API-Key", "header"),
}.WithCodec(codex.String().Refine(validate.NonEmptyString)))
type Subscribe ¶ added in v0.8.0
type Subscribe struct {
// OperationID is the unique identifier for the subscribe operation in the
// AsyncAPI spec. Used by code generators and documentation tools.
OperationID string
Summary string
Description string
Tags []string
// SchemaName, when non-empty, emits a $ref for the payload schema in the
// spec and registers the schema under that name in components/schemas.
SchemaName string
// Security, when non-nil, overrides global security for this operation.
// Pass an empty slice to declare "no auth required" for this subscription.
// nil (default) inherits global security declared via [Builder.AddGlobalSecurity].
Security []route.SecurityRequirement
}
Subscribe describes the subscribe operation on a channel (application receives). It controls the subscribe entry in the AsyncAPI spec.
Subscribe implements ChannelOpt: pass it directly to NewChannel.
type TopicParam ¶ added in v0.5.0
type TopicParam struct {
// Name is the variable name (without braces) as it appears in the topic template.
Name string
// Description is shown in the AsyncAPI spec for this parameter.
Description string
// Codec validates topic parameter values at [ChannelHandle.ValidateTopicVars] and
// [ChannelHandle.BuildTopic] time.
// When non-nil, the codec's schema is also emitted in the AsyncAPI spec.
// Nil means no runtime validation; the spec defaults to {type: string}.
Codec *codex.Codec[string]
}
TopicParam describes a {varName} placeholder in a topic template for AsyncAPI spec generation and runtime validation.
TopicParam is the single configuration point for a topic variable: it carries spec metadata (description) and an optional codec for runtime validation. The codec schema is also used to enrich the AsyncAPI parameters: block.
TopicParam is optional: the events builder auto-derives parameters from the topic template. Use TopicParam to add a description or register a codec for a specific variable.
Note: all topic variables are always required — a template cannot be resolved without every {varName} placeholder present. There is no Required field.
TopicParam implements ChannelOpt: pass it directly to NewChannel.
Entry names must correspond to {varName} placeholders in the topic template; unknown names cause Channel.Register to return an error immediately.
func (TopicParam) WithCodec ¶ added in v0.8.0
func (p TopicParam) WithCodec(c codex.Codec[string]) TopicParam
WithCodec sets the validation codec and returns the updated TopicParam.
type TopicParamError ¶ added in v0.4.0
type TopicParamError struct {
Name string // the {varName} that failed
Value string // the value that was rejected
Err error // the underlying codec error
}
TopicParamError is returned by ChannelHandle.BuildTopic and ChannelHandle.ValidateTopicVars when a topic variable fails its registered codec check.
Use errors.As to extract it and inspect the failing variable:
var paramErr events.TopicParamError
if errors.As(err, ¶mErr) {
log.Printf("bad value %q for {%s}: %v", paramErr.Value, paramErr.Name, paramErr.Err)
}
func (TopicParamError) Error ¶ added in v0.4.0
func (e TopicParamError) Error() string
func (TopicParamError) Unwrap ¶ added in v0.4.0
func (e TopicParamError) Unwrap() error
Unwrap allows errors.As and errors.Is to traverse the underlying codec error.