Plugins
Goa plugins make it possible to create new DSLs and accompanying generators. They run before rendering the final artifacts which makes it possible to alter the templates exposed by the Goa code generators, thereby, producing new kinds of outputs from any DSL.
Goa plugins repository houses a set of public goa plugins. Refer to the README in every plugin for instructions on how to use it.
Building Your Own Plugin
Plugins can be used to do a few different things:
A plugin may add its own DSL which is used alongside with the existing Goa DSL. The plugin DSL may produce completely different code or modify the existing code produced by Goa code generators.
A plugin may provide a GenerateFunc to modify the Goa generated files or to generate new files and return them to the final artifact generation.
type GenerateFunc func(genpkg string, roots []eval.Root, files []*File) ([]*File, error)
- A plugin may provide a PrepareFunc, to modify the design prior to the code being generated.
type PrepareFunc func(genpkg string, roots []eval.Root) error
Plugins register themselves using one of the RegisterPlugin, RegisterPluginFirst, or RegisterPluginLast functions.
CORS Plugin
One of the built-in plugins is the CORS plugin which adds the ability to define CORS properties on HTTP endpoints and uses the corresponding expressions to generate code that implements CORS for the API.
The CORS plugin adds its own DSL which can be used in the design as shown below:
package design
import (
. "goa.design/goa/v3/dsl"
cors "goa.design/plugins/v3/cors/dsl"
)
var _ = Service("calc", func() {
Description("The calc service exposes public endpoints that defines CORS policy.")
// Add CORS policy using the CORS DSLs
cors.Origin("/.*localhost.*/", func() {
cors.Headers("X-Shared-Secret")
cors.Methods("GET", "POST")
cors.Expose("X-Time", "X-Api-Version")
cors.MaxAge(100)
cors.Credentials()
})
Method("multiply", func() {
Description("Multiply multiplies the two integer parameters and returns the results.")
Payload(func() {
Attribute("a", Int, func() {
Description("Left operand")
})
Attribute("b", Int, func() {
Description("Right operand")
})
Required("a", "b")
})
Result(Int)
HTTP(func() {
GET("/multiply/{a}/{b}")
Response(StatusOK)
})
})
})
The design above sets up a CORS policy on all the endpoints defined in the
calc
service.
The CORS plugin registers itself by calling the RegisterPlugin
function in the
Goa codegen
package and adds its own code
generator which
implements the GenerateFunc
type.
package cors
import (
"goa.design/goa/v3/codegen"
"goa.design/goa/v3/eval"
)
func init() {
codegen.RegisterPlugin("cors", "gen", nil, Generate)
}
// Generate produces server code that handle preflight requests and updates
// the HTTP responses with the appropriate CORS headers.
func Generate(genpkg string, roots []eval.Root, files []*codegen.File) ([]*codegen.File, error) {
...
}
// cors/dsl/cors.go
package dsl
// Register code generators for the CORS plugin
import _ "goa.design/plugins/v3/cors"
This generator modifies the generated HTTP server code to handle preflight
requests by mounting the CORS
endpoint.
The Goa code generation algorithms then invoke the function which modifies the generated HTTP server package.