go-foundation

module
v2.3.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 8, 2026 License: MIT

README

go-foundation v2

A Go application foundation with development-time checks.

Zero runtime dependencies MIT

Foundation is the plumbing an application needs before it is an application: dependency injection, HTTP, actions, scheduling, configuration, caching, logging, resiliency. What v2 changes is when a mistake surfaces.

An application built this way says things the Go compiler cannot check. A contract is a type parameter, a route is a struct tag, an injected dependency is a name in a string. In v1 those relationships were resolved by reflection while the program ran, so a wrong one became a failed request. In v2 an analyzer reads them while the file is open, a generator turns them into compile-time assertions and static registries, and the editor navigates them like ordinary symbols.

Install

go get github.com/mirkobrombin/go-foundation/v2@latest
go install github.com/mirkobrombin/go-foundation/dev/v2/cmd/foundation@latest

The runtime module has no third-party dependencies. The analyzer, the generator, and the CLI live in a separate module, so an application that imports Foundation never pulls the analysis packages into its own build.

Static workflow

Declare contracts and application metadata in normal Go:

type UserStore interface {
    Find(int) (User, bool)
}

type MemoryUserStore struct {
    contracts.Implements[UserStore]
}

type GetUser struct {
    _     struct{} `method:"GET" path:"/users/{id:int}"`
    ID    int      `path:"id"`
    Users UserStore `inject:"users"`
}

func build() (*app.App, error) {
    application := app.New().Provide("users", NewMemoryUserStore())
    RegisterFoundation(application)
    _, err := application.Build()
    return application, err
}

Generate registration code and check the complete workspace:

foundation generate ./...
foundation check ./...
go test ./...

Generation writes one zz_foundation.gen.go per package that declares something, holding the contract assertions and the static constructors, and removes the file again when the declarations are gone. Commit it: that is what makes a broken contract a compile error on a machine that has never installed the CLI.

Generation is a choice, not a toll. RegisterHTTP and RegisterActionHandler still register by reflection, and foundation check reports the same problems either way, so a v1 application can move to v2 without a single generated file in its tree.

See the quickstart example, exercised by its own test.

Calling App.Listen("") binds to 127.0.0.1:8080. Pass an explicit public address only when the service is intended to accept remote traffic. Use App.ListenTLS for direct HTTPS, or terminate TLS at a trusted reverse proxy.

Layers

Layer Purpose Examples
core Runtime building blocks with no application dependency contracts, caching, validation, configuration, events, telemetry
app Application composition and boundaries DI, HTTP, actions, dispatcher, hosting, testing
dev Development-only analysis and generation foundation check, foundation generate
editors Editor-specific presentation VS Code diagnostics, CodeLens, hover, contract and dependency navigation

The analyzer enforces the dependency direction: core cannot import app, and runtime packages cannot import dev.

Development-time checks

foundation check reports:

  • invalid contracts.Implements[T] declarations;
  • invalid DI implementation and constructor registrations;
  • duplicate or malformed routes and actions;
  • route parameters without matching fields;
  • locally missing or mistyped named dependencies;
  • dispatches to locally unknown actions;
  • invalid literal scheduler registrations;
  • ignored binding errors;
  • forbidden layer imports.

The compiler remains the authority for generated contract assertions. go vet, tests, and the race detector remain part of the expected verification path.

Editor navigation

A contract is a type parameter and a dependency is a struct tag, so a Go editor cannot follow either on its own. The VS Code extension reads them and answers the two questions that matter while writing code: what implements this, and where does this come from.

Implementations of a contract shown in the VS Code peek view

The screenshot is the quickstart example. UserStore carries a CodeLens with the number of implementations found in the workspace, and clicking it opens the peek: the implementations on one side, the code of the selected one on the other. MemoryUserStore declares the relationship with contracts.Implements[UserStore], which is also a CodeLens leading back to the interface. The same navigation works between inject:"users" and Provide("users", ...), in both directions.

Assistants

foundation mcp serves the same knowledge and the same tools over the Model Context Protocol, so an assistant answers from the API catalog of the version it is working with instead of from memory, and verifies with the real analyzer, generator, compiler and tests instead of asserting.

{
  "mcpServers": {
    "foundation": { "command": "foundation", "args": ["mcp"] }
  }
}

The catalog is extracted from the source and checked in the pipeline, so the answers cannot drift from the code. See the MCP server.

Typed APIs

Named dependency keys can retain their Go type:

var usersKey = di.NewKey[UserStore]("users")

builder := di.NewBuilder()
di.ProvideKey(builder, usersKey, store)
container, err := builder.Build()
users, ok := di.ResolveKey(container, usersKey)

Actions also have a typed path:

router := actions.New()
create := actions.NewTyped[CreateUser, User]("users.create")
err := actions.HandleTyped(router, create, handler)
result, err := actions.DispatchTyped(ctx, router, create, payload)

Use strings where they are part of external metadata. Use typed APIs inside Go code when the compiler can carry the relationship.

Documentation

License

MIT

Directories

Path Synopsis
app
di
web
Package web provides a minimal API server with routing, middleware, and model binding.
Package web provides a minimal API server with routing, middleware, and model binding.
core
caching
Package caching provides a generic, thread-safe in-memory cache with TTL support.
Package caching provides a generic, thread-safe in-memory cache with TTL support.
configuration
Package configuration provides a flexible, multi-source configuration system inspired by .NET's IConfiguration pattern.
Package configuration provides a flexible, multi-source configuration system inspired by .NET's IConfiguration pattern.
configuration/source/dir
Package dir implements configuration.Provider for directories of JSON files.
Package dir implements configuration.Provider for directories of JSON files.
plugin
Package plugin provides a focused plugin registry and supporting helpers.
Package plugin provides a focused plugin registry and supporting helpers.
examples
quickstart
Package quickstart shows the static Foundation v2 workflow.
Package quickstart shows the static Foundation v2 workflow.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL