Lazy App
A small support ticket example
Follow one feature through a plain Go service, a controller, a view, and application wiring.
This is the prepared example shown on the homepage, not a transcript of an agent run. It lists two tickets from fixed sample data. It does not implement ticket creation, authentication, or durable storage.
Start with a generated GoLazy app. In these files, replace supporttickets in
imports with your application's module path. Keep the generated base controller,
embedded view setup, and default layout. Add the service, controller, and view
below, register the dependency, and add the resource to your existing routes.
The Config and entrypoint files show the wiring in a minimal app; merge that
wiring with your own configuration rather than discarding other app settings.
Ticket service
services/ticketservice/service.go
package ticketservice
import "context"
type Ticket struct {
Title string
Status string
}
type Service struct{}
type contextKey struct{}
func New(ctx context.Context) (context.Context, *Service, error, context.CancelFunc) {
service := &Service{}
return context.WithValue(ctx, contextKey{}, service), service, nil, nil
}
func FromContext(ctx context.Context) (*Service, bool) {
service, ok := ctx.Value(contextKey{}).(*Service)
return service, ok
}
func (s *Service) List() []Ticket {
return []Ticket{
{Title: "Reset my password", Status: "open"},
{Title: "Update billing email", Status: "open"},
}
}
Tickets controller
app/controllers/ticketscontroller/controller.go
package ticketscontroller
import (
"context"
"fmt"
"net/http"
"supporttickets/app/controllers"
"supporttickets/services/ticketservice"
)
type TicketsController struct {
controllers.BaseController
tickets *ticketservice.Service
}
func New(ctx context.Context) (*TicketsController, error) {
base, err := controllers.NewBaseController(ctx)
if err != nil {
return nil, err
}
tickets, ok := ticketservice.FromContext(ctx)
if !ok {
return nil, fmt.Errorf("ticket service is missing")
}
return &TicketsController{BaseController: base, tickets: tickets}, nil
}
func (c *TicketsController) Index(_ http.ResponseWriter, _ *http.Request) error {
c.Set("tickets", c.tickets.List())
return nil
}
Ticket view
app/views/tickets/index.html.tpl
<h1>Support tickets</h1>
{{range .tickets}}
<article>
<h2>{{.Title}}</h2>
<p>{{.Status}}</p>
</article>
{{else}}
<p>No tickets yet.</p>
{{end}}
Dependency registration
init/dependencies.go
package appinit
import (
"golazy.dev/lazydeps"
"supporttickets/services/ticketservice"
)
func Dependencies(deps *lazydeps.Scope) error {
_, err := lazydeps.Service(deps, "tickets", ticketservice.New)
return err
}
Resource routes
init/routes.go
package appinit
import (
"golazy.dev/lazyroutes"
"supporttickets/app/controllers/ticketscontroller"
)
func Draw(router *lazyroutes.Scope) {
router.Resources(ticketscontroller.New)
}
Application configuration
init/app.go
package appinit
import (
"golazy.dev/lazyapp"
_ "golazy.dev/lazyview/gotmpl"
"supporttickets/app"
)
func Config() lazyapp.Config {
return lazyapp.Config{
Name: "Support tickets", Drawer: Draw,
Views: app.Views, Dependencies: Dependencies,
}
}
func App() *lazyapp.App { return lazyapp.New(Config()) }
Application entrypoint
cmd/app/main.go
package main
import (
"golazy.dev/lazyapp"
"os"
appinit "supporttickets/init"
)
func main() { os.Exit(lazyapp.Run(appinit.Config())) }
The default app/views/layouts/app.html.tpl must render {{.content}}.
router.Resources exposes GET /tickets for TicketsController.Index;
the action sets template data and GoLazy renders tickets/index.
Run go test ./..., then go run ./cmd/app and open /tickets.
Keep business changes in the service as the application grows. Read the
service guide, controller guide,
and SVC article for the surrounding conventions.