tinka alpha
tinkaalpha

Create the App

This chapter creates the App the rest of the tutorial builds on. You will learn how to:

Overview

The skeleton starter kit gives a new App the structure every later chapter relies on: configuration read from the environment, one place for routes, and tests ready to run. act serve then runs the App and builds it again each time you save a file, so you start it once, in a terminal of its own, and keep it running while you work.

Install the tools

Tinka has two commands, both installed with Go's own tooling. tinka creates Apps, and act runs Commands inside an App, such as act serve.

  1. Install the Tinka CLI

    Terminal
    go install github.com/mucolabs/tinka/cmd/tinka@latest
  2. Install act

    Terminal
    go install github.com/mucolabs/tinka/cmd/act@latest

Go places both binaries in $(go env GOPATH)/bin, which must be on your PATH. Installation shows how to check them, and the setting Go needs during the alpha, while the Tinka repository is private.

Create the App

Run tinka new with the directory to create. It asks which starter kit to use: choose skeleton. Answer yes when it asks whether to initialize a git repository, since the last chapter versions the App from its git tags.

Terminal
tinka new blog
Output
  Copying the skeleton kit ............................................ 5ms DONE
  Installing dependencies ............................................ 70ms DONE
  Initializing a git repository ....................................... 9ms DONE
Created blog with the skeleton kit

  cd blog
  act serve

tinka new copies the kit, requires the version of Tinka it was installed at, downloads the dependencies and generates the App's APP_KEY into .env. It also trusts the new directory, so act builds and runs the App's code without asking first. Move into the App:

Terminal
cd blog

Look around the App

The skeleton puts each kind of code in its own package. These are the ones the tutorial changes:

Path Holds
main.go The entry point: it loads the configuration and runs the App
start/app.go App, which builds the App and adds its services and Commands
start/routes.go Routes, which registers the App's routes
app/handlers The handlers that answer requests
config The configuration, read from the environment at boot
tests tests.App, which builds the App for tests, and the tests themselves

Folder structure describes every file. For now, two matter. start/routes.go registers the home route, and the health check routes the last chapter uses:

start/routes.go
package start

import (
	"github.com/mucolabs/tinka"
	"github.com/mucolabs/tinka/health"

	"blog/app/handlers"
)

// Routes registers the App's routes. It runs as the App starts, after the
// providers registered their services, so it can resolve them; an error
// stops the App before it serves.
func Routes(app *tinka.App) error {
	app.Get("/", handlers.Home)

	// GET /health/live and GET /health/ready, for load balancers. Add a
	// check for each service the App can't serve without, such as its
	// database.
	app.Health(health.New(health.DiskSpace("/")))
	return nil
}

The home route's handler returns a struct, which the App sends as JSON:

app/handlers/home.go
// Package handlers holds the App's handlers: the functions that answer
// requests.
package handlers

import "github.com/mucolabs/tinka"

type greeting struct {
	Hello string `json:"hello"`
}

// Home answers GET / with JSON.
func Home(c *tinka.Ctx) (greeting, error) {
	return greeting{Hello: "world"}, nil
}

Run the App

Start the dev server from the App's directory, in a terminal you leave open:

Terminal
act serve
Output
  INFO  Watching for changes (inotify, 8 directories)
  INFO  Built in 1.3s, serving http://localhost:3000
[01:07:43.106] INFO: server started addr=127.0.0.1:35265 took=694.584µs

The lines starting with INFO come from act serve, and the timestamped ones from the App's own logger. act serve listens on localhost:3000 and forwards each request to the App, which listens on a private port of its own: that's the address the App logs. In another terminal, request the home route:

Terminal
curl localhost:3000/
Output
{"hello":"world"}

The dev server's terminal logs the request, with its status, its duration and the request's ID:

Output
[01:07:43.123] INFO: request method=GET path=/ status=200 took=83.306µs request_id=T2BGTXNW3JFUQLWPTFHY3S6PJW

Save a change

act serve builds the App again each time you save a Go file, while the running App keeps answering. Make a mistake on purpose to see what a failed build does: remove , nil from the handler's return, and save.

app/handlers/home.go
// Home answers GET / with JSON.
func Home(c *tinka.Ctx) (greeting, error) {
	return greeting{Hello: "world"}, nil
	return greeting{Hello: "world"}
}

The build fails, and the dev server prints the compiler's error:

Output
  ERROR  The build failed after 149ms; the App keeps running its previous code
# blog/app/handlers
app/handlers/home.go:13:9: not enough return values
	have (greeting)
	want (greeting, error)

curl still gets {"hello":"world"} from the App that was running before the change, so a typo never takes the App down. A page you open in the browser shows the error instead, where you're looking. Put , nil back and save again. The new build replaces the old App in a few milliseconds:

Output
[01:08:03.974] INFO: server stopped
  INFO  Built in 965ms, restarted in 34ms
[01:08:04.015] INFO: server started addr=127.0.0.1:35265 took=805.55µs

Requests that arrive during the restart wait for the new App instead of failing. Keep act serve running: every change in the next chapters takes effect when you save it.

Recap

You installed tinka and act, created the blog App from the skeleton starter kit, and ran it with act serve, which rebuilds and restarts it on every save and keeps the old App serving when a build fails. Next, Routes and handlers gives the App its first posts.

See also: Installation, Folder structure, Development environment setup, Commands reference