Documentation
¶
Overview ¶
Package reqreply provides a transport-agnostic request-reply API layer for async transports (ZeroMQ, MQTT 5, AMQP RPC, etc.).
It follows the same declare → register → handle pattern as api/events and api/rest. Route is the reqreply analogue of [rest.Route]: a typed request-reply declaration with a topic/address instead of an HTTP method+path.
The protocol is just a server string in Builder.AddServer — the same Route declaration works for any transport. Adapters accept *RouteHandle directly.
Usage ¶
// Declare once — no HTTP method, just a topic.
var ComputeRoute = reqreply.NewRoute[ComputeReq, ComputeResp](
"compute/add",
computeReqCodec, computeRespCodec,
reqreply.RouteMeta{OperationID: "computeAdd", Summary: "Add two integers."},
reqreply.ErrorPattern[domain.ConflictError, ErrorPayload](errorPayloadCodec,
func(e domain.ConflictError) (ErrorPayload, error) {
return ErrorPayload{Code: "conflict", Message: e.Error()}, nil
},
).WithCode("conflict").WithDescription("Business conflict.").WithSchemaName("ConflictError"),
)
// Register with a Builder to get a RouteHandle and an AsyncAPI 3.0 spec.
builder := reqreply.NewBuilder(reqreply.Info{Title: "Compute API", Version: "1.0.0"})
builder.AddServer("zmq", reqreply.Server{URL: "tcp://localhost:5556", Protocol: "zmq"})
// OR: builder.AddServer("mqtt5", reqreply.Server{URL: "mqtt://broker:1883", Protocol: "mqtt5"})
handle, err := ComputeRoute.Register(builder)
// Same handle — works with any request-reply adapter. Handler/encode
// errors matching a declared ErrorPattern get the typed payload as the
// reply instead of a plain-text error string:
zmqadapter.Serve(ctx, sock, handle, fn, zmqadapter.ServeOptions{Observer: obs})
mqtt5adapter.Serve(ctx, client, router, handle, fn, mqtt5.ServeOptions{Observer: obs})
// AsyncAPI 3.0 spec with request-reply reply: block, plus the
// ErrorPattern-derived reply-error channel/operation:
doc, _ := builder.AsyncAPISpec()
yaml, _ := doc.MarshalYAML()
Error-path ergonomics ¶
ErrorPattern is the codec-first, runtime-wired error declaration — the request-reply analogue of [rest.ErrorPattern] and [events.ErrorChannel]: declare a typed error payload for a matched error type (direct or mapped mode), and [mqtt5.Serve]/[zeromq.Serve]/[zeromq.ServeRouter] automatically send it on handler/encode failure instead of a plain-text error string. ErrorPattern also drives the AsyncAPI reply-error channel/operation that ErrorReplyMeta previously required a separate declaration for — one declaration now produces both. ErrorReplyMeta remains available unchanged for spec-only declarations that need no runtime dispatch.
Index ¶
- type Builder
- type DuplicateRouteError
- type ErrorPatternOpt
- func (o ErrorPatternOpt[E, B]) WithChannelAddress(addr string) ErrorPatternOpt[E, B]
- func (o ErrorPatternOpt[E, B]) WithCode(code string) ErrorPatternOpt[E, B]
- func (o ErrorPatternOpt[E, B]) WithDescription(desc string) ErrorPatternOpt[E, B]
- func (o ErrorPatternOpt[E, B]) WithOperationID(id string) ErrorPatternOpt[E, B]
- func (o ErrorPatternOpt[E, B]) WithSchemaName(name string) ErrorPatternOpt[E, B]
- type ErrorPatternResponse
- type ErrorReplyMeta
- type FormatOptError
- type Info
- type MergeFieldTypeError
- type MergedTopicParam
- type MissingRouteParamError
- type Route
- type RouteHandle
- func (h *RouteHandle[Req, Resp]) BuildTopic(vars map[string]string) (string, error)
- func (h *RouteHandle[Req, Resp]) DecodeMerged(payload []byte, topicVars map[string]string) (Req, error)
- func (h *RouteHandle[Req, Resp]) ErrorResponseFor(err error) (ErrorPatternResponse, bool, error)
- func (h *RouteHandle[Req, Resp]) MergeFields() []codex.FieldCodec[Req]
- func (h *RouteHandle[Req, Resp]) ValidateTopicVars(vars map[string]string) error
- func (h *RouteHandle[Req, Resp]) WithFormats(fmts ...format.Format[Resp]) *RouteHandle[Req, Resp]
- func (h *RouteHandle[Req, Resp]) WithRequestFormats(fmts ...format.Format[Req]) *RouteHandle[Req, Resp]
- type RouteMeta
- type RouteOpt
- type RouteParamError
- type Server
- type TopicParam
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 Route registrations and produces an AsyncAPI 3.0 document with request-reply operations.
Create a Builder with NewBuilder, add servers via [AddServer], register routes via Route.Register, and call [AsyncAPISpec] to produce the document.
func NewBuilder ¶
NewBuilder returns a Builder initialised with the given Info.
func (*Builder) AddServer ¶
AddServer registers a named server in the AsyncAPI document. Servers appear in output in registration order.
Use Protocol: "zmq" for ZeroMQ servers, "mqtt5" for MQTT 5.0, etc.
func (*Builder) AppendTo ¶
func (b *Builder) AppendTo(db *asyncapi.DocumentBuilder) error
AppendTo writes all request-reply channels registered on this Builder into db. Servers and schemas owned by this Builder are NOT written — the caller is responsible for configuring those on db.
Use AppendTo to combine request-reply channels with pub/sub channels from api/events.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()
type DuplicateRouteError ¶
type DuplicateRouteError struct {
// Topic is the topic that was registered more than once.
Topic string
}
DuplicateRouteError is returned by Route.Register when a route with the same topic has already been registered with the Builder.
var dup reqreply.DuplicateRouteError
if errors.As(err, &dup) {
slog.Error("duplicate route", "topic", dup.Topic)
}
func (DuplicateRouteError) Error ¶
func (e DuplicateRouteError) Error() string
func (DuplicateRouteError) LogValue ¶
func (e DuplicateRouteError) LogValue() slog.Value
LogValue implements slog.LogValuer for structured logging.
type ErrorPatternOpt ¶ added in v0.12.0
ErrorPatternOpt is the RouteOpt value returned by ErrorPattern.
func ErrorPattern ¶ added in v0.12.0
func ErrorPattern[E error, B any]( codec codex.Codec[B], mapFn ...func(E) (B, error), ) ErrorPatternOpt[E, B]
ErrorPattern declares a codec-backed typed error reply for a matched error type — the request-reply analogue of [rest.ErrorPattern] and [events.ErrorChannel]. Unlike REST, reqreply has no HTTP status; the declaration is simply "when a handler error matches E, reply with this codec-backed payload" instead of a plain-text error string.
Two modes, mirroring [rest.ErrorPattern]:
- Direct: no mapFn provided, E must be assignable to B.
- Mapped: mapFn(E) produces B.
Matching is type-only via errors.As; the first declared ErrorPattern (in NewRoute option order) whose type matches wins — the same deterministic precedence used by REST/events.
ErrorPattern ALSO drives the AsyncAPI reply-error channel/operation that ErrorReplyMeta previously had to be declared separately for — one declaration now produces both the runtime dispatch AND the spec entry. Use ErrorPatternOpt.WithCode/ErrorPatternOpt.WithDescription/ ErrorPatternOpt.WithSchemaName/ErrorPatternOpt.WithChannelAddress/ ErrorPatternOpt.WithOperationID to customize the generated spec entry (defaults mirror ErrorReplyMeta's defaults). ErrorReplyMeta remains available unchanged for spec-only declarations that need no runtime dispatch (e.g. documenting an error reply produced by a different mechanism entirely).
reqreply.NewRoute[ComputeReq, ComputeResp]("compute/add", reqCodec, respCodec,
reqreply.ErrorPattern[domain.ConflictError, ErrorPayload](errorPayloadCodec,
func(e domain.ConflictError) (ErrorPayload, error) {
return ErrorPayload{Code: "conflict", Message: e.Error()}, nil
},
),
)
func (ErrorPatternOpt[E, B]) WithChannelAddress ¶ added in v0.12.0
func (o ErrorPatternOpt[E, B]) WithChannelAddress(addr string) ErrorPatternOpt[E, B]
WithChannelAddress returns a copy of o with ChannelAddress set, overriding the generated reply-error channel address (mirrors ErrorReplyMeta.ChannelAddress).
func (ErrorPatternOpt[E, B]) WithCode ¶ added in v0.12.0
func (o ErrorPatternOpt[E, B]) WithCode(code string) ErrorPatternOpt[E, B]
WithCode returns a copy of o with Code set — used to derive the generated reply-error channel/operation IDs and address (mirrors ErrorReplyMeta.Code). Defaults to a sanitized form of E's type name when not set.
func (ErrorPatternOpt[E, B]) WithDescription ¶ added in v0.12.0
func (o ErrorPatternOpt[E, B]) WithDescription(desc string) ErrorPatternOpt[E, B]
WithDescription returns a copy of o with Description set (mirrors ErrorReplyMeta.Description).
func (ErrorPatternOpt[E, B]) WithOperationID ¶ added in v0.12.0
func (o ErrorPatternOpt[E, B]) WithOperationID(id string) ErrorPatternOpt[E, B]
WithOperationID returns a copy of o with OperationID set, overriding the generated receive operation ID (mirrors ErrorReplyMeta.OperationID).
func (ErrorPatternOpt[E, B]) WithSchemaName ¶ added in v0.12.0
func (o ErrorPatternOpt[E, B]) WithSchemaName(name string) ErrorPatternOpt[E, B]
WithSchemaName returns a copy of o with SchemaName set — emits a $ref for the payload schema in components/schemas (mirrors ErrorReplyMeta.SchemaName).
type ErrorPatternResponse ¶ added in v0.12.0
type ErrorPatternResponse struct {
// Body is the JSON-encoded typed error payload.
Body []byte
// Value is the typed payload before encoding — useful for adapters that
// want to re-encode with a non-JSON format.
Value any
}
ErrorPatternResponse is the adapter-ready payload produced by RouteHandle.ErrorResponseFor when a declared ErrorPattern matches.
type ErrorReplyMeta ¶ added in v0.12.0
type ErrorReplyMeta struct {
// Code identifies the error variant (e.g. "conflict", "validation").
// It is used to derive channel/operation IDs when explicit IDs are not set.
Code string
// Description describes the error reply operation.
Description string
// Schema is the payload schema for this error reply message.
Schema schema.Schema
// SchemaName, when non-empty, emits a $ref and registers Schema in
// components/schemas.
SchemaName string
// OperationID, when non-empty, overrides the generated receive operation ID.
OperationID string
// ChannelAddress, when non-empty, overrides the generated reply-error
// channel address. Default: "<topic>/reply/error[/<code>]".
ChannelAddress string
}
ErrorReplyMeta declares one additional reply error message for AsyncAPI rendering.
It adds a dedicated reply-error channel+operation to the generated spec. Runtime adapter behavior is unchanged: this option is documentation/contract metadata only (same role as RouteMeta).
Schema is required; when SchemaName is non-empty, the schema is emitted via $ref in components/schemas.
type FormatOptError ¶ added in v0.12.0
type FormatOptError struct {
// Direction is "request" (from [RequestFormats]) or "response" (from [Formats]).
Direction string
Err error
}
FormatOptError is returned by Route.Register when RequestFormats or Formats was declared with formats for a type that does not match the route's actual request/response type parameter.
func (FormatOptError) Error ¶ added in v0.12.0
func (e FormatOptError) Error() string
func (FormatOptError) LogValue ¶ added in v0.12.0
func (e FormatOptError) LogValue() slog.Value
LogValue implements slog.LogValuer for structured logging.
type Info ¶
Info is an alias for asyncapi.Info. Using the alias avoids duplicating fields and keeps the two in sync automatically.
type MergeFieldTypeError ¶ added in v0.12.0
type MergeFieldTypeError struct {
Err error
}
MergeFieldTypeError is returned by Route.Register when a merge field registered via NewTopicParam has the wrong type parameter for the route's Req type — mirrors [rest.MergeFieldTypeError] exactly.
func (MergeFieldTypeError) Error ¶ added in v0.12.0
func (e MergeFieldTypeError) Error() string
func (MergeFieldTypeError) LogValue ¶ added in v0.12.0
func (e MergeFieldTypeError) LogValue() slog.Value
LogValue implements slog.LogValuer for structured logging.
type MergedTopicParam ¶ added in v0.12.0
type MergedTopicParam[Req any] struct { TopicParam // contains filtered or unexported fields }
MergedTopicParam is returned by NewTopicParam. It is the reqreply mirror of [rest.MergedPathParam]/[events.MergedTopicParam]: the registered field's setter merges the extracted topic variable into the decoded Req via RouteHandle.DecodeMerged; the getter extracts the topic variable's value from Req for the client-side single-call convenience (adapter-specific `CallHandle`, e.g. `mqtt5.CallHandle`/ `zeromq.CallHandle`). Request-side only — see [routeBuilder.mergeFields].
func NewTopicParam ¶ added in v0.12.0
func NewTopicParam[Req any]( name string, codec codex.Codec[string], get func(Req) string, set func(*Req, string), ) MergedTopicParam[Req]
NewTopicParam declares a topic variable that is BOTH validated against codec AND automatically merged into Req by RouteHandle.DecodeMerged — one declaration instead of a TopicParam plus a separate codex.Field. All topic variables are always required, matching plain TopicParam's existing "no Required field" rationale.
reqreply.NewRoute[ComputeReq, ComputeResp]("compute/{tenantID}/add",
computeReqCodec, computeRespCodec,
reqreply.NewTopicParam("tenantID", codex.String().Refine(validate.NonEmptyString),
func(r ComputeReq) string { return r.TenantID },
func(r *ComputeReq, v string) { r.TenantID = v },
),
)
func (MergedTopicParam[Req]) WithDescription ¶ added in v0.12.0
func (p MergedTopicParam[Req]) WithDescription(desc string) MergedTopicParam[Req]
WithDescription sets the PARAMETER-level description and returns the updated value.
type MissingRouteParamError ¶
type MissingRouteParamError struct {
// Name is the {varName} placeholder that was missing from vars.
Name string
}
MissingRouteParamError is returned by RouteHandle.BuildTopic and RouteHandle.ValidateTopicVars when a required topic variable is absent from the vars map. It mirrors [events.MissingTopicVarError].
var missing reqreply.MissingRouteParamError
if errors.As(err, &missing) {
slog.Warn("missing topic var", "name", missing.Name)
}
func (MissingRouteParamError) Error ¶
func (e MissingRouteParamError) Error() string
func (MissingRouteParamError) LogValue ¶
func (e MissingRouteParamError) LogValue() slog.Value
LogValue implements slog.LogValuer for structured logging.
type Route ¶
type Route[Req, Resp any] struct { // contains filtered or unexported fields }
Route[Req,Resp] is a typed request-reply route for async transports (ZeroMQ, MQTT 5, AMQP, etc.). It is the api/reqreply analogue of [rest.Route], which is for HTTP. The key difference is that a Route has a topic/address instead of an HTTP method and path.
NewRoute is infallible — it only captures the spec. Validation runs at Route.Register time.
Typical usage:
var ComputeRoute = reqreply.NewRoute[ComputeReq, ComputeResp](
"compute/add",
computeReqCodec, computeRespCodec,
reqreply.RouteMeta{OperationID: "computeAdd", Summary: "Add two integers."},
)
// Register with a builder to get an AsyncAPI spec + a RouteHandle:
builder := reqreply.NewBuilder(reqreply.Info{Title: "API", Version: "1.0.0"})
builder.AddServer("zmq", reqreply.Server{URL: "tcp://...", Protocol: "zmq"})
handle, err := ComputeRoute.Register(builder)
// Adapters accept *reqreply.RouteHandle:
zmqadapter.Serve(ctx, sock, handle, fn, zmqadapter.ServeOptions{Observer: obs})
mqtt5adapter.ServeRequestReply(ctx, client, router, handle, fn, mqtt5.ServeOptions{Observer: obs})
func NewRoute ¶
func NewRoute[Req, Resp any]( topic string, reqCodec codex.Codec[Req], respCodec codex.Codec[Resp], opts ...RouteOpt, ) Route[Req, Resp]
NewRoute creates a Route spec from a topic, codecs, and variadic opts. NewRoute is infallible — validation runs at Route.Register time.
NewRoute is a free function (not a method) because Go requires type parameters on free functions, not on method receivers.
func (Route[Req, Resp]) ClientHandle ¶
func (r Route[Req, Resp]) ClientHandle() *RouteHandle[Req, Resp]
ClientHandle returns a RouteHandle for client-side use without registering with a Builder. No spec registration occurs.
Use ClientHandle when only the client side needs codec and route definitions (no AsyncAPI spec, no server), or when sharing a Route definition between server and client in the same binary without a second builder registration.
The returned handle has the same Decode / Encode / EncodeRequest / DecodeResponse codec helpers and BuildTopic / ValidateTopicVars methods as a handle returned by Route.Register.
Example — client-only usage (no builder required):
var ComputeRoute = reqreply.NewRoute[ComputeReq, ComputeResp](
"compute/add", computeReqCodec, computeRespCodec,
)
// Client side — no builder needed.
handle := ComputeRoute.ClientHandle()
resp, err := mqtt5adapter.Call(ctx, client, router, handle, req, mqtt5adapter.CallOptions{})
Mirrors [rest.Route.ClientHandle].
func (Route[Req, Resp]) Register ¶
func (r Route[Req, Resp]) Register(b *Builder) (*RouteHandle[Req, Resp], error)
Register registers the route with b and returns a RouteHandle.
Returns DuplicateRouteError if a route with the same topic has already been registered with b.
Use RouteHandle.WithRequestFormats and RouteHandle.WithFormats after Register to configure multi-format request/response handling.
type RouteHandle ¶
type RouteHandle[Req, Resp any] struct { // Topic is the request address (e.g. "compute/add"). Topic string // Decode deserialises and validates a JSON request payload into Req. // All Refine constraints on the request codec run automatically. Decode func(payload []byte) (Req, error) // Encode serialises Resp to JSON bytes. Encode func(resp Resp) ([]byte, error) // EncodeRequest serialises Req to JSON bytes for use as an outgoing request // payload. It is the client-side complement of Decode. EncodeRequest func(req Req) ([]byte, error) // DecodeResponse deserialises and validates a JSON reply payload into Resp. // It is the client-side complement of Encode. DecodeResponse func(payload []byte) (Resp, error) // RequestFormats, when non-empty, overrides the default JSON format for // decoding incoming request payloads. The adapter uses RequestFormats[0] // instead of Decode when present. // Configure via [RouteHandle.WithRequestFormats]. RequestFormats []format.Format[Req] // Formats, when non-empty, overrides the default JSON format for encoding // reply payloads. The adapter uses Formats[0] instead of Encode when present. // Configure via [RouteHandle.WithFormats]. Formats []format.Format[Resp] // contains filtered or unexported fields }
RouteHandle is returned by Route.Register. It holds the codec-backed Decode/Encode helpers and is passed directly to request-reply adapters (adapters/zeromq, adapters/mqtt5).
RouteHandle mirrors [rest.RouteHandle] and [events.ChannelHandle]: it is a value that callers pass around and store. No magic, no global state.
func (*RouteHandle[Req, Resp]) BuildTopic ¶
func (h *RouteHandle[Req, Resp]) BuildTopic(vars map[string]string) (string, error)
BuildTopic substitutes {varName} placeholders in the route's topic template with the values provided in vars, validating each against its registered TopicParam codec (if any).
All template variables must be present in vars; missing variables return a MissingRouteParamError. Values are validated before substitution; codec failures return a RouteParamError identifying the variable name and value. Keys in vars that do not appear in the template are silently ignored.
Mirrors [events.ChannelHandle.BuildTopic].
topic, err := computeRoute.BuildTopic(map[string]string{"tenantID": "acme"})
// topic = "compute/acme/add"
func (*RouteHandle[Req, Resp]) DecodeMerged ¶ added in v0.12.0
func (h *RouteHandle[Req, Resp]) DecodeMerged(payload []byte, topicVars map[string]string) (Req, error)
DecodeMerged decodes the request payload (via the route's registered format) AND merges every NewTopicParam-registered topic variable into the SAME Req value, using codex.DecodeVars internally — the reqreply mirror of [rest.RouteHandle.DecodeMerged]/[events.ChannelHandle.DecodeMerged]. Additive — RouteHandle.Decode is unchanged; DecodeMerged behaves identically to a bare Decode when the route declares no merge-capable topic params (MergeFields() is empty).
The payload decode error (if any) is returned FIRST, before the topic-var merge step runs — matching the REST/events precedent. The merge step itself collects every field's failure via codex.DecodeVars (never stops at the first one).
func (*RouteHandle[Req, Resp]) ErrorResponseFor ¶ added in v0.12.0
func (h *RouteHandle[Req, Resp]) ErrorResponseFor(err error) (ErrorPatternResponse, bool, error)
ErrorResponseFor returns the first declared ErrorPattern match for err (matching via errors.As, in declaration order), or (ErrorPatternResponse{}, false, nil) when none match.
A non-nil third return value indicates the matched pattern's mapping or encoding failed — callers should treat this as a terminal error for that pattern (do not fall through to other patterns).
func (*RouteHandle[Req, Resp]) MergeFields ¶ added in v0.12.0
func (h *RouteHandle[Req, Resp]) MergeFields() []codex.FieldCodec[Req]
MergeFields returns the merge-capable fields registered via NewTopicParam — feed them directly into codex.DecodeVars/ codex.EncodeVars, or use RouteHandle.DecodeMerged for the closed-loop convenience method.
func (*RouteHandle[Req, Resp]) ValidateTopicVars ¶
func (h *RouteHandle[Req, Resp]) ValidateTopicVars(vars map[string]string) error
ValidateTopicVars validates extracted topic variable values against the registered TopicParam codecs. Call this after extracting vars from an incoming request topic to ensure each variable satisfies its codec constraints.
Returns RouteParamError for the first variable that fails its codec. Variables without a registered codec are skipped. Missing required variables return MissingRouteParamError.
Mirrors [events.ChannelHandle.ValidateTopicVars].
func (*RouteHandle[Req, Resp]) WithFormats ¶
func (h *RouteHandle[Req, Resp]) WithFormats(fmts ...format.Format[Resp]) *RouteHandle[Req, Resp]
WithFormats sets the formats used for encoding reply payloads and returns the updated handle. Adapters use Formats[0] for encoding when non-empty, falling back to RouteHandle.Encode (JSON) otherwise.
Mirrors [rest.RouteHandle.WithFormats].
func (*RouteHandle[Req, Resp]) WithRequestFormats ¶
func (h *RouteHandle[Req, Resp]) WithRequestFormats(fmts ...format.Format[Req]) *RouteHandle[Req, Resp]
WithRequestFormats sets the formats the route accepts for request body decoding and returns the updated handle. Adapters use RequestFormats[0] for decoding when non-empty, falling back to RouteHandle.Decode (JSON) otherwise.
Mirrors [rest.RouteHandle.WithRequestFormats].
type RouteMeta ¶
type RouteMeta struct {
// OperationID is the base name for the two generated operations.
// The send operation is named "send<OperationID>" and the receive operation
// is named "receive<OperationID>Reply". When empty, the topic is used
// (e.g. "compute/add" → "sendComputeAdd" / "receiveComputeAddReply").
OperationID string
// Summary is a short human-readable summary of the route.
Summary string
// Description is a longer human-readable description for the send operation.
Description string
// Tags attach arbitrary labels to the operations in the AsyncAPI spec.
Tags []string
// ReqSchemaName, when non-empty, registers the request payload schema in
// components/schemas and emits a $ref. Use to share schemas across routes.
ReqSchemaName string
// RespSchemaName, when non-empty, registers the response payload schema in
// components/schemas and emits a $ref.
RespSchemaName string
}
RouteMeta holds metadata for a Route registration. It controls the generated AsyncAPI operation IDs, summary, description, and schema refs.
RouteMeta implements RouteOpt: pass it directly to NewRoute.
type RouteOpt ¶
type RouteOpt interface {
// contains filtered or unexported methods
}
RouteOpt is the sealed interface for variadic NewRoute options.
The following types implement RouteOpt:
- RouteMeta — operation metadata (OperationID, Summary, Description, Tags, schema names)
- TopicParam — topic template variable with optional codec and description
- ErrorReplyMeta — additional AsyncAPI reply error channel/message declarations (spec-only)
- ErrorPattern — codec-backed typed error reply (runtime dispatch + spec entry)
func Formats ¶ added in v0.12.0
Formats declares the formats a request-reply route can produce for response encoding — the RouteOpt equivalent of calling RouteHandle.WithFormats after Route.Register. See RequestFormats.
func RequestFormats ¶ added in v0.12.0
RequestFormats declares the formats a request-reply route accepts for request decoding — the RouteOpt equivalent of calling RouteHandle.WithRequestFormats after Route.Register. Declarable inline in NewRoute's variadic opts, which means it also works through ports.ReqReplyPattern.Opts with zero changes to the ports package.
A mismatched type is only detectable once Req is concrete — Route.Register returns FormatOptError in that case.
type RouteParamError ¶
type RouteParamError struct {
Name string // the {varName} that failed
Value string // the value that was rejected
Err error // the underlying codec error
}
RouteParamError is returned by RouteHandle.BuildTopic and RouteHandle.ValidateTopicVars when a topic variable fails its registered codec check. It mirrors [events.TopicParamError].
var paramErr reqreply.RouteParamError
if errors.As(err, ¶mErr) {
slog.Warn("bad topic var", "error", paramErr)
}
func (RouteParamError) Error ¶
func (e RouteParamError) Error() string
func (RouteParamError) LogValue ¶
func (e RouteParamError) LogValue() slog.Value
LogValue implements slog.LogValuer for structured logging.
type TopicParam ¶
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 [RouteHandle.ValidateTopicVars] and
// [RouteHandle.BuildTopic] time.
// When non-nil, the codec's schema is also emitted in the AsyncAPI spec.
// Nil means no runtime validation.
Codec *codex.Codec[string]
}
TopicParam describes a {varName} placeholder in a topic template. It is the api/reqreply analogue of [events.TopicParam].
TopicParam is optional: RouteHandle.BuildTopic and RouteHandle.ValidateTopicVars use registered params to validate variable values. Use TopicParam when you want runtime codec validation on 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 RouteOpt: pass it directly to NewRoute.
Entry names must correspond to {varName} placeholders in the topic template.
var ComputeRoute = reqreply.NewRoute[ComputeReq, ComputeResp](
"compute/{tenantID}/add",
computeReqCodec, computeRespCodec,
reqreply.RouteMeta{OperationID: "computeAdd"},
reqreply.TopicParam{
Name: "tenantID",
Description: "Tenant namespace for this computation.",
}.WithCodec(codex.String().Refine(validate.NonEmptyString)),
)
func (TopicParam) WithCodec ¶
func (p TopicParam) WithCodec(c codex.Codec[string]) TopicParam
WithCodec sets the validation codec and returns the updated TopicParam.