Scaffolding
This guide covers creating code with act's generators. You will learn how to:
- Create a handler, a provider, a Command, middleware or a test
- See what a generator changes before it changes anything
- Change the stubs generators write files from
- Register what a generator couldn't, by hand
Overview
A generator writes a new file into the App and adds the line that registers it, such as the route of a new handler. It saves typing the same code each time, and it puts everything where the folder structure says it goes, so every App reads alike.
Generators write files from stubs: Go files with placeholders, such as {{ .Type }}, that the generator fills in. The App can replace any stub with its own.
Create code
Each generator is an act make: Command that takes a singular name:
act make:handler post --resourceCREATE app/handlers/posts.go
UPDATE start/routes.go
+ app.Get("/posts", handlers.ListPosts)
+ app.Get("/posts/{id}", handlers.ShowPost)
+ app.Post("/posts", handlers.CreatePost)
+ app.Put("/posts/{id}", handlers.UpdatePost)
+ app.Delete("/posts/{id}", handlers.DeletePost)| Command | Creates | Registers |
|---|---|---|
| act make:handler post | app/handlers/post.go, one handler | its route in start/routes.go |
| act make:handler post --resource | app/handlers/posts.go, the five handlers of a REST resource | their routes |
| act make:provider database | app/providers/database_provider.go | app.Provide in start/app.go |
| act make:command posts:publish | app/commands/posts_publish.go | app.Command in start/app.go |
| act make:middleware auth | app/middleware/auth.go | nothing, or app.Use in start/kernel.go with --global |
| act make:test posts | tests/functional/posts_test.go, an HTTP test | nothing |
In an App created from the core starter kit, every file goes in the App's root package, and the registrations go after tinka.New in the function that creates the App.
Names
A generator derives every name from the one you type, the Go way: post gives the type Post, the file post.go, the plural Posts and the route /posts; user_id gives UserID; and a suffix that repeats the kind is dropped, so make:provider DatabaseProvider still creates DatabaseProvider. When the plural rules get a word wrong, give the plural:
act make:handler cactus --resource --plural cactiA name Go already uses, such as type or string, and one whose file Go would build only on one system, such as legacy_windows, are refused, with the reason.
Check before writing
--dry-run prints what a generator would create and change, and writes nothing:
act make:provider database --dry-runA generator never replaces a file that exists: it stops before writing anything, and --force replaces it. Running a generator twice adds no registration twice: one that's already there is skipped.
Change the stubs
act publish:stubs copies the default stubs into the App's stubs/ directory. From then on, generators use the App's copy:
act publish:stubs make/handler---
to: {{ .Dir }}/{{ .File }}.go
---
package {{ .Package }}
import "github.com/mucolabs/tinka"
// {{ .Type }} answers GET {{ .Path }}.
func {{ .Type }}(c *tinka.Ctx) (string, error) {
return "{{ .Type }}", nil
}The front matter's to: is where the file goes, so a stub can also move it. A stub holds placeholders and nothing else: a variant is another stub, such as make/handler_resource.
A stub with a placeholder that doesn't exist, or that renders Go that doesn't parse, fails with the stub's path, and writes nothing.
Register by hand
A generator edits start/app.go, start/routes.go and start/kernel.go by adding lines after those of the same kind, and leaves every other line as it was. When it can't find where a line goes, such as when you've moved the App's assembly elsewhere, it still creates the file, writes nothing else, and tells you the exact line to add, and where:
Error: created app/providers/cache_provider.go, but couldn't register it.
Fix: In start/app.go, in App, after tinka.New (it has no function App that uses tinka), add:
app.Provide(&providers.CacheProvider{})
and import "blog/app/providers".Agents get the same steps in error.details, with the code codemod_manual.
Generators match the App's Tinka
The starter kits pin act in the App's go.mod. A globally installed act hands its generators to that copy, so the code they write always matches the version of Tinka the App uses. That copy is built from what the App's go.mod points to, so act does this only for an App you trust; otherwise it uses its own generators and says so.
See also: Folder structure, Commands reference, Creating Commands