Using CODL to Generate Cookoo Routes
Cookoo is a tool for rapidly build Go applications. A central part of any Cookoo app is its registry of routes. A route maps a particular request to a series of tasks that Cookoo will perform in response.
Cookoo routes are written in code and compiled into the application. While I love this feature of Cookoo, I do sometimes find the syntax to be a little clumsy. For example, a Cookoo route definition might look something like this:
reg.Route("default", "Default route").
Does(fmt.Template, "out").
Using("template").WithDefault("Hello World").
Does(fmt.Println, "print").
Using("content").From("cxt:out")
As routes get longer, this syntax feels tedious. I wanted something that felt, to be perfectly honest, more like SQL. I wanted something that did for Cookoo routes what SASS or LESS do for CSS. And so I wrote codl.
CODL is a simple domain-specific language (DSL) for defining Cookoo routes. A complete CODL file looks like this (app.codl):
IMPORT
github.com/Masterminds/cookoo/fmt
ROUTE default "Default route"
DOES fmt.Template out
USING template "Hello World"
DOES fmt.Println print
USING content FROM cxt:out
This declares exactly the same route as the previous code example. But its syntax is simpler.
Like SASS or LESS, codl comes with a command-line tool that can transform a
codl file into Go source. You can call it as codl build -d DIRECTORY
, which
will transform all codl files in DIRECTORY, or you can tell codl to continue to
run and watch a directory for changes, compiling any time it finds any change.
$ codl watch -d routes/
[INFO] Watching routes for changes to .codl files.
[INFO] routes/app.codl has changed. Updating. ("routes/app.codl": CREATE)
[INFO] Translated routes/app.codl to routes/app.go
When codl transforms a codl file, the generated result looks something like this:
package routes
// This file is auto-generated by Codl.
import (
"github.com/Masterminds/cookoo"
"github.com/Masterminds/cookoo/fmt"
)
func AppRoutes(reg *cookoo.Registry) {
reg.Route("default", "Default route").
Does(fmt.Template, "out").
Using("template").WithDefault("Hello World").
Does(fmt.Println, "print").
Using("content").From("cxt:out")
}
In my main app, I can include all of these generated routes by doing something like this:
func main() {
reg, router, cxt := cookoo.Cookoo()
routes.AppRoutes(reg)
cli.New(reg, router, cxt).Run("default")
}
The routes.ApPRoute()
function is automatically generated by codl based on
the file name (app.codl
).
Codl files are a nicety for small apps, but when writing large applications in Cookoo, having an easy to read (and easy to search) file format for your routes can make a huge diference in terms of maintainability.