# Scaffolding

> Create handlers, providers, Commands, middleware and tests with act make, register them in the App's code, and change the stubs they're written from.

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](../../folder-structure.md) 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:

```sh
act make:handler post --resource
```

```text title="Output"
CREATE 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:

```sh
act make:handler cactus --resource --plural cacti
```

A 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:

```sh
act make:provider database --dry-run
```

A 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:

```sh
act publish:stubs make/handler
```

```text title="stubs/make/handler.stub"
---
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`.

::::options

:::option{name="{{ .Type }}" type="placeholder"}
The exported name: `BlogPost`.
:::

:::option{name="{{ .Var }}" type="placeholder"}
The unexported name: `blogPost`.
:::

:::option{name="{{ .File }}" type="placeholder"}
The file name, without `.go`: `blog_post`.
:::

:::option{name="{{ .Plural }}" type="placeholder"}
The exported plural: `BlogPosts`. `{{ .PluralFile }}` is `blog_posts`, and `{{ .PluralWords }}` is `blog posts`.
:::

:::option{name="{{ .Route }}" type="placeholder"}
The resource's route: `/blog-posts`. `{{ .Path }}` is the singular one: `/blog-post`.
:::

:::option{name="{{ .Command }}" type="placeholder"}
The Command's name: `blog-post`, or `posts:publish` as typed.
:::

:::option{name="{{ .Package }}" type="placeholder"}
The package the file belongs to, such as `handlers`, and `{{ .Dir }}` its directory, such as `app/handlers`.
:::

:::option{name="{{ .Module }}" type="placeholder"}
The App's module path, for imports of its own packages: `blog`.
:::

::::

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:

```text title="Output"
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](../../reference/commands.md#act-trust); otherwise it uses its own generators and says so.

See also: [Folder structure](../../folder-structure.md), [Commands reference](../../reference/commands.md#act-makehandler), [Creating Commands](../command-line/commands.md)
