Templates are the implementation for your generator.
They are parameterized files which are filled in
with data from the schema and user input.
Generators have several kinds of files that end up in the output
Once Templates - used to generate a single file, like main.go or index.js
Repeated Templates - generate a file for each element, like routes in this example
Partial Templates - reusable template snippets which are available in all full templates
Static Files - copied directly into the output, bypassing the template engine
Config Files - generate yaml or json into the output, bypassing the template engine
Templates are based on Go text/template with extra helpers and conventions.
We will cover the basics in the the-walkthrough and they should be familiar to other text templating systems.
Read [template writing(/code-generation/template-writing/) to learn more about the details.
Once Templates
These files are needed once for every server we generate.
Some have minimal templating and others loop over values, like router.go.
package main
import (
"context""os""os/signal""time""github.com/labstack/echo/v4")
var PORT string = ":8080"funcmain() {
// create echo server
e := echo.New()
e.HideBanner = true// add middleware
err :=setupMiddleware(e)
if err !=nil {
panic(err)
}
// setup router
err = setupRouter(e)
if err !=nil {
panic(err)
}
//
// code to run server and enable graceful shutdown
//
// Start server with background goroutine
gofunc() {
if err := e.Start(PORT); err !=nil {
e.Logger.Info("shutting down the server")
}
}()
// Wait for interrupt signal to gracefully shutdown the server with
// a timeout of 10 seconds.
quit :=make(chan os.Signal)
signal.Notify(quit, os.Interrupt)
// wait on a quit signal
<-quit
// start the shutdown process
ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
defercancel()
if err := e.Shutdown(ctx); err !=nil {
e.Logger.Fatal(err)
}
}
templates/router.go
package main
import (
"net/http""github.com/labstack/echo/v4""github.com/labstack/echo-contrib/echoprometheus" {{ ifgt (len .SERVER.Routes ) 1 }}
"{{ .SERVER.GoModule }}/routes" {{ end }}
)
funcsetupRouter(e *echo.Echo) error {
// Internal routes
e.GET("/internal/alive", func(c echo.Context) error {
return c.NoContent(http.StatusOK)
})
{{ if .SERVER.Prometheus }}
e.GET("/internal/metrics", echoprometheus.NewHandler())
{{ end }}
// Application routes group
g := e.Group("")
// Register the routes
{{ range$R := .SERVER.Routes -}}
routes.{{ $R.Name }}Routes(g)
{{ end }}
returnnil}
We separate the handler into a template which uses the partial.
This is for demonstration purpose here and will be more useful
in the “full-example” section where the implementation is more complete.
templates/route.go
package routes
import (
"net/http""github.com/labstack/echo/v4")
// {{ .ROUTE.Name }}Routes sets up the routes in a router Group
func {{ .ROUTE.Name }}Routes(G *echo.Group) {
g := G.Group("{{ .ROUTE.Path }}{{ range $PATH := .ROUTE.Params }}/:{{$PATH}}{{ end }}")
g.{{.ROUTE.Method}}( "", {{.ROUTE.Name}}Handler)
// we'll handle sub-routes here in "full-example"
}
// Handler implementation is in a partial template
{{ template "handler.go" .ROUTE }}
partials/handler.go
{{ $ROUTE := . }}
func {{ $ROUTE.Name }}Handler(c echo.Context) (err error) {
// process any path and query params
{{ range$P :=$ROUTE.Params }}
{{ $P }} := c.Param("{{ $P }}")
{{ end }}
{{ range$Q :=$ROUTE.Query }}
{{ $Q }} := c.QueryParam("{{ $Q }}")
{{ end }}
{{ if$ROUTE.Body }}
// custom body
{{ $ROUTE.Body }}
{{ else }}
// default body
c.String(http.StatusNotImplemented, "Not Implemented")
{{ end }}
returnnil}
Static Files
By default, anything in the static/ dir will be copied into the output dir.
You can configure one or more manually via the generator by setting the Statics field on your generator.
Config Files
Rendered Output Files
Here we can see the result of code generation for a sample of the files.
We will actually generate these in the next section.
They are provided here so you can see the input / output pairs on a single page.
package main
import (
"net/http""github.com/labstack/echo-contrib/echoprometheus""github.com/labstack/echo/v4""hof.io/docs/example/routes")
funcsetupRouter(e *echo.Echo) error {
// Internal routes
e.GET("/internal/alive", func(c echo.Context) error {
return c.NoContent(http.StatusOK)
})
e.GET("/internal/metrics", echoprometheus.NewHandler())
// Application routes group
g := e.Group("")
// Register the routes
routes.EchoQRoutes(g)
routes.EchoPRoutes(g)
routes.HelloRoutes(g)
returnnil}
output/routes/Hello.go
package routes
import (
"net/http""github.com/labstack/echo/v4")
// HelloRoutes sets up the routes in a router Group
funcHelloRoutes(G *echo.Group) {
g := G.Group("/hello")
g.GET("", HelloHandler)
// we'll handle sub-routes here in "full-example"
}
// Handler implementation is in a partial template
funcHelloHandler(c echo.Context) (err error) {
// process any path and query params
msg := c.QueryParam("msg")
// custom body
if msg =="" {
msg = "hello world" }
c.String(http.StatusOK, msg)
returnnil}