Functions #
Template functions are used to call the Go functions from the templates and use their results in the template rendering.
Besides the standard functions, the biggest part of functions are provided by sprout package. There are a lot of functions to work with types, numbers, environment variables, filesystem, etc.
Full list of sprout functions.
Another part of functions is provided by the go-asyncapi itself and have functionality specific to the go-asyncapi tool.
Sections below describe the functions provided by go-asyncapi.
Code generation #
The functions described in this sect6ion have the go name prefix, which means they return the Go code snippets.
goLit #
func goLit(value any) (string, error)
Converts the given value to a Go literal.
If value is a common.GolangType, it returns its usage code – equivalent of {{ goUsage value }}.
If value is one of primitive Go types, it returns the value as a Go literal. Otherwise, function panics.
Examples:
{{ goLit 42 }}returns42.
{{ goLit "foo" }}returns"foo".
If
.Typeis pointer toMySchemastruct, then{{ goLit .Type }}produces*MySchema.
goIDLower #
func goIDLower(value any) string
Converts value to a correct Go identifier and returns it in unexported form, i.e. starting from lowercase letter.
For common.Artifact value the function uses the artifact’s Name (calling its .Name method).
If value is string, function converts it to a valid Go identifier. For other argument types the function panics.
Examples:
If
.Typeis pointer toMySchemastruct, then{{ goIDLower .Type }}producesmySchema.
{{ goIDLower "foo_bar http" }}returnsfooBarHTTP.
goID #
func goID(value any) string
Converts value to a correct Go identifier and returns it in exported form, i.e. starting from uppercase letter.
For common.Artifact value the function returns the artifact’s Name (calling its .Name method).
If value is string, function converts it to a valid Go identifier. For other argument types the function panics.
Examples:
If
.Typeis pointer toMySchemastruct, then{{ goID .Type }}producesMySchema.
{{ goID "foo_bar http" }}returnsFooBarHTTP.
goComment #
func goComment(text string) string
Converts the given text to a Go comment. If text contains newlines, it is converted to a multi-line comment.
Examples:
{{ goComment "This is a comment" }} returns // This is a comment.
{{ goComment "This is a\nmulti-line comment" }} returns
/*
This is a
multi-line comment */
goPkg #
func goPkg(obj common.Artifact) (string, error)
Consume a name from any generated package seamlessly.
- If
objis pinned to a package other than the current one, function adds an import to current file if necessary and returns the imported name prefix – package_name+’.'. - If
objis pinned to current package, function does nothing and returns the empty string. - If
objnot pinned at all, the function returns errortmpl.ErrNotPinned.
Examples:
If
.Typeis defined inschemas/my_schema.goand the current file ischannels/my_channel.go, then{{ goPkg .Type }}MySchemaproducesschemas.MySchemaadding an importimport schemas.
If
.Typeis defined inchannels/my_schema.go(i.e. in current packagechannels) and the current file ischannels/my_channel.go, then{{ goPkg .Type }}MySchemaproducesMySchemaand function does nothing.
goPkgUtil #
func goPkgUtil(parts ...string) (string, error)
Consume a name from util code seamlessly.
Joins parts into the import path, adds an import to current file if necessary and returns the imported name
prefix – package_name+’.’. If util code was not generated for a particular protocol, returns error tmpl.ErrNotPinned.
Examples:
{{goPkgUtil "amqp"}}ServerBindingsproducesamqp.ServerBindingsadding an import, e.g.example.com/foo/bar/asyncapi/proto/amqp.
goPkgImpl #
func goPkgImpl(parts ...string) (string, error)
Consume a name from implementation code seamlessly.
Joins parts into the import path, adds an import to current file if necessary and returns the imported name
prefix – package_name+’.’. If implementation code was not generated for a particular protocol, returns error tmpl.ErrNotPinned.
Examples:
{{goPkgImpl "amqp"}}NewClientproducesamqp.NewClientadding an import, e.g.example.com/foo/bar/asyncapi/proto/amqp.
goPkgRun #
func goPkgRun(parts ...string) (string, error)
Consume a name from runtime package seamlessly.
Joins parts into the import path, adds an import to current file if necessary and returns the imported name
prefix – package_name+’.'.
Examples:
{{goPkgRun}}ParamStringproducesrun.ParamStringadding an importgithub.com/bdragon300/go-asyncapi/run.
goPkgExt #
func goPkgExt(parts ...string) (string, error)
Consume a name from any external package seamlessly.
Joins parts into the import path, adds an import to current file if necessary and returns the imported name
prefix – package_name+’.'.
Because the function arguments are joined into an import part, the expressions
{{goPkgExt "golang.org/x/net/ipv4"}},{{goPkgExt "golang.org" "x/net/ipv4"}},{{goPkgExt "golang.org" "x" "net" "ipv4" }}are equivalent.
Examples:
{{goPkgExt "io"}}Copyproducesio.Copyadding an importio.
goDef #
func goDef(r common.GolangType) (string, error)
Pins a type to the current package and returns the Go definition code. If type is not pinnable, then it just return the definition code.
Examples:
If
.Typeislang.GoStructwith name “MySchema” , then{{ goDef .Type }}produces the code:type MySchema struct { Foo string }
If
.Typeis type alias with name “Foo” tointtype, then{{ goDef .Type }}producestype Foo int.
goUsage #
func goUsage(r common.GolangType) (string, error)
Returns the Go usage code for the given Go type artifact, automatically adding the necessary package imports if needed.
- If
ris pinned to a package other than the current one, function adds an import to current file if necessary and returns the imported name prefix – package_name+’.'. - If
ris pinned to current package, function does nothing and returns the empty string. - If
rnot pinned at all, the function returns errortmpl.ErrNotPinned.
Examples:
If
.TypeisMySchemastruct defined inschemas/my_schema.goand the current file ischannels/my_channel.go, then{{ goUsage .Type }}producesschemas.MySchemaadding an importimport schemas.
If
.TypeisMySchemastruct defined inchannels/my_schema.go(i.e. in current packagechannels) and the current file ischannels/my_channel.go, then{{ goUsage .Type }}producesMySchemawithout adding any imports.
If
.Typeis pointer to the inline anonymous struct (that can’t be pinned, since it can’t have definition),
then{{ goUsage .Type }}produces the code:*struct { Foo string }
If
.Typeis the primitive typeint, then{{ goUsage .Type }}producesint.
Codegen helpers #
These functions are helper functions to work with artifacts. They don’t produce any Go code.
pin #
func pin(a common.Artifact) (string, error)
Pins (i.e. associates) the given artifact to the current rendered go package. If the artifact is already pinned, does nothing. If the artifact is not pinnable, returns an error.
Always returns empty string.
Example:
{{ pin . }}pins the.artifact to the current rendered Go package.
isVisible #
func isVisible(a common.Artifact) common.Artifact
Returns nil if the given artifact should NOT be rendered in the generated code due to go-asyncapi configuration,
x-ignore flag set in the AsyncAPI entity definition or other reasons.
Example:
{{ with isVisible .Type }}{{ goDef . }}{{ end }}produces the type definition only if.Typeis visible, otherwise it skips the body of the “with” statement due tonilfunction result.
once #
func once(r any) any
Accepts any comparable object and returns it back only first time during the go-asyncapi
execution, all next calls with the same object return nil.
Useful to avoid duplicate code generation. The functionality is similar to sync.Once in Go.
Example:
{{ with once .FooBar }} {{ goDef . }} {{ end }}
innerType #
func innerType(r common.GolangType) common.GolangType
Returns the type that is wrapped by wrapper type (pointer, type redefinition). If r is not a wrapper type, returns nil.
Example:
If
.Typeis alang.Pointerorlang.GoTypeDefinitionwrapping anlang.GoStructobjectMySchema, then the expression{{ with innerType .Type }}{{ goUsage . }}{{ end }}producesMySchemain both cases.If
.Typeis something else, “goUsage” won’t execute.
impl #
func impl(protocol string) *tmpl.ImplementationCodeInfo
Returns the tmpl.ImplementationCodeInfo object describing the implementation code for the given protocol.
If the implementation code was not generated for this protocol, returns nil.
Example:
The template
{{ with impl "kafka" }}{{ .Protocol }}{{ end }}produces the protocol name only if the implementation code was generated for “kafka” protocol.
utilCode #
func utilCode(protocol string) *common.UtilCodeInfo
Returns the tmpl.UtilCodeInfo object describing the util code for the given protocol.
If the util code was not generated for this protocol, returns nil.
Example:
The template
{{ with utilCode "kafka" }}{{ .Protocol }}{{ end }}produces the protocol name only if the util code was generated for “kafka” protocol.
runtimeExpression #
func runtimeExpression(a tmpl.runtimeExpressionArtifact, target *lang.GoStruct, addValidationCode bool) *tmpl.RuntimeExpressionInfo
Function compiles the Go code, that recursively extracts a value based on runtime expression and target struct.
Arguments are:
- artifact that contains the runtime expression:
CorrelationIDorOperationReplyAddress - struct artifact to extract a value from
- flag to include the validation code such as array bound check or map key presence check, that is typically used for getter methods
If a is nil or is not visible, function returns nil. If error occurred during the runtime expression compilation,
function is also returns nil.
Typical usage:
{{- with runtimeExpression .CorrelationID .OutType false}}
func (m *{{ $.OutType | goID }}) SetCorrelationID(value {{goUsage .OutputType}}) *{{ goID $.OutType }} {
{{.InputVar}} := m.{{toString .Expression.StructFieldKind | toTitleCase}}
{{template "code/runtimeExpression/setterBody" .}}
m.{{toString .Expression.StructFieldKind | toTitleCase}} = {{.InputVar}}
return m
}
{{- end}}
{{- with runtimeExpression .CorrelationID $.InType false}}
func (m {{ $.InType | goID }}) CorrelationID() (value {{goUsage .OutputType}}, err error) {
{{.InputVar}} := m.{{toString .Expression.StructFieldKind}}
{{template "code/runtimeExpression/getterBody" .}}
{{if .CodeSteps}}value = {{.OutputVar}}{{end}}
return
}
{{- end}}
Template execution #
Although the Go template language has the template directive that executes another template, it the compile-time directive,
so it doesn’t support the dynamic template names.
The functions described in this section are used to execute the templates dynamically, at runtime.
tmpl #
func tmpl(templateName string, ctx any) (string, error)
Looks up the template with the given name and executes it passing the ctx as a context object.
If the template is not found or template execution fails, returns an error.
Example:
{{ tmpl (print "code/proto/" $protocol "channel/newFunction/block1") $ }}executes thecode/proto/kafka/channel/newFunction/block1template if$protocol == "kafka", passing the current template context (i.e.$) to it.
tryTmpl #
func tryTmpl(templateName string, ctx any) (string, error)
The same as tmpl, but if the template is not found, returns an empty string instead of raising an error.
Useful when you want to execute a template only if it exists.
Example:
{{ with tryTmpl (print "code/proto/" $protocol "channel/newFunction/block1") $ }} {{.}} {{ end }}This produces the output of the template
code/proto/kafka/channel/newFunction/block1for$protocol == "kafka"only if this template exists. Otherwise, this snippet does nothing.
Other helpers #
toQuotable #
func toQuotable(s string) string
Returns the quotable string for the given s, which can be safely wrapped in double quotes in the generated Go code.
The function escapes the double quotes, escape sequences, control characters, non-printable characters.
Example:
{{ toQuotable "foo\n \"bar\" \xFFbaz" }}producesfoo\n \"bar\" \xFFbaz.
ellipsisStart #
func ellipsisStart(maxLen int, s string) string
The function truncates a string to a maxLen characters from the end and prepends an ellipsis ("…") if the
string exceeds that width.
Example:
{{ "Hello, World!" | ellipsisStart 10 }}returns... World!.
debug #
func debug(args ...any) string
Prints the given arguments to the logging output with the debug level and returns an empty string.
mapping #
mapping(v any, variantPairs ...any) any
Looks for a key equal to v in key-value pairs and returns the associated value or nil if key not found.
Example:
{{ mapping "spam" "foo" "bar" "spam" "eggs" 123 456 }}produceseggs
{{ with mapping "?" "foo" "bar" "spam" "eggs"}}{{.}}{{else}}Nothing{{end}}producesNothing
toList #
toList(v any) ([]any, error)
Converts any array/slice v to []any slice. Returns error if v is not array or slice.
hasKey #
hasKey(key any, m any) (bool, error)
Returns true if key is present in map m. Return error if m is not a map or key type is not compatible to map’s key type.