apigenie-generatorAsyncAPI clientsclient go (AsyncAPI)
client go (AsyncAPI)
Generate a Go Kafka client package for the Kafka channels of an AsyncAPI document.
Usage
apigenie-generator client go [...OPTIONS] INPUT_FILE
Description
apigenie-generator client go generates from OpenAPI documents (see
apigenie-generator client go) and from AsyncAPI 3.x documents,
telling them apart by their openapi or asyncapi field. Documents referencing other files are
bundled first.
From an AsyncAPI document it generates a Go module (Go 1.22) with one package, using the Kafka
client franz-go (github.com/twmb/franz-go/pkg/kgo, pinned
at v1.18.1 in go.mod, with a complete go.sum). By default the client is the counterpart of
the application the document describes: it sends the messages of the application’s receive
operations and receives those of its send operations. Set the perspective option to
application to generate the described application’s side instead.
apigenie-generator server go generates the other
side as an application with its own main.go.
The generator writes the Kafka channels: the channels of servers with the kafka or
kafka-secure protocol, and channels with a Kafka binding in documents without servers. Channels
of other protocols are skipped and reported as info.
With perspective: application, the client of the Carpet Express Event Platform sends the
shipment events and requests labels:
client, err := events.NewClient(events.Options{
Brokers: []string{"localhost:9092"},
ClientID: "label-printer",
})
if err != nil {
log.Fatal(err)
}
defer client.Close()
// a sent operation with several messages takes any of them
err = client.SendPublishShipmentEvents(ctx, delivered)
// request/reply: waits for the reply with the request's correlation id
reply, err := client.RequestLabelRender(ctx, request)
switch reply := reply.(type) {
case events.LabelRendered:
fmt.Println(reply.Payload.URL)
case events.LabelRenderFailed:
fmt.Println(reply.Payload.Title)
}
In the default perspective, it receives them and renders the labels:
type labelFarm struct{}
func (labelFarm) OnRenderLabel(ctx context.Context, message events.RenderLabel) (events.RequestLabelRenderReply, error) {
var reply events.LabelRendered
reply.Key = message.Key
reply.Payload = render(message.Payload)
return reply, nil // sent to TopicLabelRenderResults with the request's correlation id
}
func (labelFarm) OnUnknown(ctx context.Context, record *kgo.Record) error { return nil }
// received operations are consumed in the background until Close
err = client.ListenRequestLabelRender(labelFarm{})
err = client.ListenPublishShipmentEvents(shipmentTracker{})
The package is named by package_name, --package-name or the document’s title (letters and
digits, lower case):
| File | Contents |
|---|---|
types.gen.go |
the types of the schemas the payloads use: structs with json tags, enums, and unions as a struct whose Value holds one variant of a sealed interface; each with a Validate method |
messages.gen.go |
a struct per message (Key, Headers, Payload), its headers struct and header constants, and the code writing, reading and validating records |
kafka.gen.go |
the server hosts, topics, group and client ids, the handler and message interfaces, and Client |
runtime_*.gen.go |
the Kafka runtime (consumers, requesters, headers), validation, Nullable[T], Date |
go.mod, go.sum |
the module, requiring franz-go |
- The client.
NewClient(options)creates the producer and, for every operation with a reply, one consumer of its reply topic that all of that operation’s requests share.Closestops the listeners, commits the offsets of the records they handled, leaves their consumer groups and closes the clients.Optionstakes the brokers,ClientID(replacing the generatedProducerClientID),ClientOptions(franz-go options added to every client, e.g.kgo.SASL,kgo.DialTLSConfigorkgo.AllowAutoTopicCreation),GroupIDs(consumer groups by operation id),OnErrorandReplyTimeout. - Sent operations.
Send<Operation>(ctx, message)validates the message, writes its key, its headers (constant headers such as thece_specversionandce_typeof CloudEvents included) and its JSON payload to the operation’s topic, and returns once the brokers have it. With several messages, it takes an interface (PublishShipmentEventsMessage) that each of them implements. - Request/reply with a reply channel:
Request<Operation>(ctx, message)sets a new correlation id unless the message has one, sends the request and waits for the reply with that id until the context is done (Options.ReplyTimeout, 30 seconds by default, when the context has no deadline). It returns the reply message, or an interface of the reply messages (RequestLabelRenderReply) when there are several. An operation named after the verb isn’t repeated:requestLabelRendergivesRequestLabelRender. - Received operations.
Listen<Operation>(handler)consumes the operation’s topic in the background, in its consumer group, untilClose. The handler interface (PublishShipmentEventsHandler) has anOn<Message>method per message andOnUnknown. Several messages are told apart by a payload property or a header with a distinct constant value (e.g.typeorce_type); otherwise the first message whose payload decodes strictly and is valid is chosen. Records that aren’t valid messages, and handler errors, go toOptions.OnError(logged by default). An operation with a reply getsOn<Message>(ctx, message) (Reply, error): the reply is sent to the reply topic with the request’s correlation id copied.
Group and client ids come from the Kafka operation bindings as for apigenie-generator server go.
Not supported, and reported as warnings: Avro payloads and payloads of other non-JSON schema
formats (the messages are skipped, and operations left without a message too), reply addresses
given by runtime expressions, and Kafka topics with parameters. Security (SASL/SCRAM, mTLS) is not
configured: pass kgo.SASL or kgo.DialTLSConfig in Options.ClientOptions. Validate
doesn’t check not, if/then/else and dependencies, tuples are []any (only their item
count is checked), and contentEncoding: base64 strings stay strings.
Extensions
| Extension | Effect |
|---|---|
x-go-name |
name of the type of a schema, or of the field of a property |
x-go-type |
Go type of a schema, e.g. decimal.Decimal; with x-go-type-import: {path: ...} for its package |
x-go-type-skip-optional-pointer |
the optional property isn’t a pointer |
x-go-json-ignore |
the field gets the tag json:"-" |
x-omitempty |
true or false overrides the omitempty of the field |
x-enum-varnames, x-enumNames |
names of the enum constants |
x-enum-descriptions |
comments of the enum constants |
x-apigenie.codegen.name |
name of the type of a component schema, when it has no x-go-name |
x-apigenie.codegen.disabled |
true on a channel or an operation leaves it out (with the operations of a channel left out) |
The extensions can live in an overlay for this target instead of in the document, e.g.
go.overlay.yaml:
overlay: 1.0.0
info:
title: Go types
version: 1.0.0
actions:
- target: $.components.schemas.Order
update:
x-go-name: PurchaseOrder
- target: $.components.schemas.Order.properties.total
update:
x-go-type: decimal.Decimal
x-go-type-import:
path: github.com/shopspring/decimal
apigenie-generator client go asyncapi.yaml --overlay go.overlay.yaml -o out
Options
-c, –config
Path to the configuration file to use. See the “Configuration” section for more information.
–overlay OVERLAY
Path to an OpenAPI Overlay (1.0 to 1.2) applied to the input before generating, e.g. one setting the
extensions of the “Extensions” section. Can be repeated: the overlays apply in order, after those
listed under commands.generate.client_go.overlay in the configuration file (with paths relative to
it). Warnings and errors about a value an overlay set point to the overlay. The overlays apply to
the AsyncAPI document bundled with the files it references.
–strict
Makes an overlay action whose target selects nothing an error (exit status 2, nothing is generated)
instead of a warning (OVERLAY:LINE:COL: action #N (TARGET) selects no nodes.).
-o, –output
Directory where the module is generated.
–package-name
Name of the Go package, as letters and digits in lower case (carpet-express-events gives
carpetexpressevents); defaults to the title of the API (events when it gives no valid
name). Its kebab case is the base of default group and client ids.
–package-version
Ignored: Go modules have no version in go.mod.
-p, –property
Applies to OpenAPI documents only; using it with an AsyncAPI document is an error.
Configuration
The options are read from the asyncapi section of the configuration of apigenie-generator client go;
its other keys configure the generation from OpenAPI documents.
version: '1.0'
commands:
generate:
client_go:
asyncapi:
module_path: github.com/acme/events
package_name: events
initialisms: [SKU]
perspective: counterpart
| Option | Description |
|---|---|
module_path |
Module path of go.mod (default: example.com/<package>) |
package_name |
Name of the package, a lower-case Go identifier (default: from --package-name or the title) |
initialisms |
Words written in capitals in identifiers, besides the common ones (ID, URL, …) |
perspective |
counterpart (default): the counterpart of the described application; application: the described application, sending what it sends |