App

Application Startup

Trace how a GoLazy application is constructed and started.

By Guillermo Alvarez - Published - Updated

Start from main

The executable entry point stays small:

func main() {
    if err := appinit.App().ListenAndServe(); err != nil {
        log.Fatal(err)
    }
}

App() returns a fully constructed application. ListenAndServe starts the HTTP server.

Construct the app

init/app.go calls lazyapp.New:

func App() *lazyapp.App {
    return lazyapp.New(lazyapp.Config{
        Name:         "sample_app",
        Drawer:       Draw,
        Public:       app.Public,
        Views:        app.Views,
        Dependencies: Dependencies,
    })
}

That call initializes application dependencies before SEO defaults, then wires the renderer, route scope, dispatcher, asset registry, helpers, and public asset fallback.

Initialize shared dependencies

Dependencies runs once during application construction:

func Dependencies(deps *lazydeps.Scope) error {
    _, err := lazydeps.Service(deps, "helloworldservice", func(ctx context.Context) (
        context.Context,
        helloworldservice.Service,
        error,
        context.CancelFunc,
    ) {
        service := helloworldservice.New()
        return helloworldservice.WithContext(ctx, service), service, nil, nil
    })
    return err
}

Controllers resolve shared dependencies from this context during request-local construction.

Initialize SEO defaults

lazyapp.Config.SEO runs after Dependencies, so application-wide metadata defaults can read dependency-backed values from the app context:

func App() *lazyapp.App {
    return lazyapp.New(lazyapp.Config{
        Name:         "sample_app",
        Drawer:       Draw,
        Public:       app.Public,
        Views:        app.Views,
        Dependencies: Dependencies,
        SEO:          SEO,
    })
}

Keep that function in init/seo.go. Read SEO And Sitemaps.

Draw routes

The app passes a framework-created route scope to Draw:

func Draw(router *lazyroutes.Scope) {
    router.Resources(homecontroller.New, func(home *lazyroutes.Resource) {
        home.Singular("home")
        home.Plural("home")
        home.Path("")
    })
}

Draw only registers routes. It does not create the mux, dispatcher, public fallback, or server.

Choose the address

ListenAndServe reads ADDR, then PORT, then falls back to 127.0.0.1:3000:

ADDR=127.0.0.1:4000 ./sample-app
PORT=4000 ./sample-app

A numeric ADDR or PORT value is treated as a port. A full address is passed to the underlying server.

CONTROL_PLANE_ADDR activates the default control plane during ListenAndServe. If it matches the app address, probes are mounted into the app server. If it differs, GoLazy starts a second server for the control plane.