This example will use the AsyncAPI official example of the HelloWorld.
The code for this example have already been generated and can be
read here, in the subdirectories app/
and user/
. You can execute examples with make examples
, or just one with
EXAMPLE=<example> make examples
where the example is <example>/<broker>
(here EXAMPLE=helloworld/nats
).
In order to recreate the code for user and application, you have to run this command:
# Install the tool
go install github.com/lerenn/asyncapi-codegen/cmd/asyncapi-codegen@latest
# Generate the code from the asyncapi file
asyncapi-codegen -i examples/helloworld/v3/asyncapi.yaml -p main -o ./helloworld.gen.go
We can then go through the helloworld.gen.go
file to understand what will be used.
Here is the code that is generated for the application side, with corresponding comments:
// AppController is the struct that you will need in order to interact with the
// event broker from the application side. You will generate this with the
// NewAppController function below.
type AppController struct
// NewAppController will create a new App Controller and will connect the
// BrokerController that you pass in argument to subscription and publication method.
func NewAppController(bs BrokerController, options ...ControllerOption) *AppController
// Close function will clean up all resources and subscriptions left in the
// application controller. This should be call right after NewAppController
// with a `defer`
func (ac *AppController) Close(ctx context.Context)
// SubscribeToAllChannels will subscribe to all channels that the application should listen to.
//
// In order to use it, you'll have to implement the AppSubscriber interface and
// pass it as an argument to this function. Thus, the subscription will automatically
// call the corresponding function when it will receive a message.
//
// In the HelloWorld example, only one function will listen on application side,
// making it a bit overkill. You can directly use the SubscribeToSayHelloFromHelloChannel
// method.
func (ac *AppController) SubscribeToAllChannels(ctx context.Context, as AppSubscriber) error
// SubscribeToReceiveHelloOperation will subscribe to new messages on the "hello"
// channel, specified in the "ReceiveHello" operation.
// It will expect messages as specified in the AsyncAPI specification.
//
// You just have to give a function that match the signature of the callback and
// then process the received message.
//
// The `done` argument is true when the subscription is closed. It can be used to
// cleanup resources, such as channels.
//
// The subscription will be canceled if the context is canceled, if the subscription
// is explicitely unsubscribed or if the controller is closed
func (ac *AppController) SubscribeToReceiveHelloOperation(ctx context.Context, fn func(msg SayHelloMessage)) error
// UnsubscribeFromReceiveHelloOperation will unsubscribe only the subscription
// on the "ReceiveHello" operation.
//
// It should be only used when wanting specifically that, otherwise the clean up
// will be handled by the Close function.
func (ac *AppController) UnsubscribeFromReceiveHelloOperation(ctx context.Context)
And here is an example of the application that could be written to use this generated code (you can also find it here):
import(
"github.com/lerenn/asyncapi-codegen/pkg/extensions/brokers/nats"
// ...
)
func main() {
// Create a NATS controller
broker, _ := nats.NewController("nats://nats:4222")
defer broker.Close()
// Create a new application controller
ctrl, _ := NewAppController(broker)
defer ctrl.Close(context.Background())
// Subscribe to HelloWorld messages
// Note: it will indefinitely wait for messages as context has no timeout
log.Println("Subscribe to hello world...")
ctrl.SubscribeToReceiveHelloOperation(context.Background(), func(_ context.Context, msg SayHelloMessage) {
log.Println("Received message:", msg.Payload)
})
defer ctrl.UnsubscribeFromReceiveHelloOperation(context.Background())
// Process messages until interruption signal
// ...
}
Here is the code that is generated for the user side, with corresponding comments:
// UserController is the struct that you will need in order to interact with the
// event broker from the user side. You will generate this with the
// NewUserController function below.
type UserController struct
// NewUserController will create a new User Controller and will connect the
// BrokerController that you pass in argument to subscription and publication method.
func NewUserController(bs BrokerController, options ...ControllerOption) *UserController
// Close function will clean up all resources and subscriptions left in the
// application controller. This should be call right after NewAppController
// with a `defer`
func (cc *UserController) Close(ctx context.Context)
// SendToReceiveHelloOperation will publish a hello world message on the "hello"
// channel as specified in the "ReceiveHello" operation.
func (cc *UserController) SendToReceiveHelloOperation(ctx context.Context, msg SayHelloMessage) error
And here is an example of the user that could be written to use this generated code (you can also find it here):
import(
"github.com/lerenn/asyncapi-codegen/pkg/extensions/brokers/nats"
// ...
)
func main() {
// Create a NATS controller
broker, _ := nats.NewController("nats://nats:4222")
defer broker.Close()
// Create a new user controller
ctrl, _ := NewUserController(broker)
defer ctrl.Close(context.Background())
// Send HelloWorld
// Note: it will indefinitely wait to publish as context has no timeout
log.Println("Publishing 'hello world' message")
if err := ctrl.SendToReceiveHelloOperation(context.Background(), SayHelloMessage{
Payload: "HelloWorld!",
}); err != nil {
panic(err)
}
// ...
}
According to the specification that you pass in parameter, some types will also be Here is the ones generated for the HelloWorld example:
// SayHelloMessage is the message expected for 'ReceiveHello' operation
type SayHelloMessage struct {
// Payload will be inserted in the message payload
Payload string
}