Documentation
¶
Overview ¶
Package inceptools is the application factory: the one call that turns a set of modules into a running, observable, gracefully-stopping HTTP service.
One call replaces the hundred lines of wiring every service otherwise writes for itself. What it assembles, in the order that is correct:
container → providers registered, nothing constructed yet middleware → request id, recover, headers, logging, identity, timeout routes → every app mounted under the version prefix, and recorded health → /healthz (liveness), /readyz (readiness), /health (detail) lifecycle → OnInit, listen, OnReady, signal, drain, OnShutdown
A minimal service:
func main() {
var cfg Config
if err := config.Load(&cfg); err != nil { log.Fatal(err) }
app := inceptools.New(inceptools.Options{
Service: "compute", Version: build.Version,
Addr: fmt.Sprintf(":%d", cfg.Port), Prefix: "/api/v1",
})
di.MustSupply(app.Container, db)
if err := app.Mount(catalog.Descriptor(), billing.Descriptor()); err != nil { log.Fatal(err) }
if err := app.Run(context.Background()); err != nil { log.Fatal(err) }
}
Index ¶
- Constants
- type Application
- func (a *Application) API() fiber.Router
- func (a *Application) Mount(descriptors ...module.Descriptor) error
- func (a *Application) MountApps(apps ...module.App) error
- func (a *Application) RouteTable() string
- func (a *Application) RoutesJSON() ([]byte, error)
- func (a *Application) Run(ctx context.Context) error
- func (a *Application) Seed(ctx context.Context) error
- func (a *Application) Shutdown(ctx context.Context) error
- func (a *Application) WriteRoutes(path string) error
- type Options
Constants ¶
const Version = "1.0.0"
Version is the framework's own version, reported on the service's health detail endpoint so you can tell which build of the framework is deployed.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Application ¶
type Application struct {
// Fiber is the underlying server. Reach for it when the framework does
// not cover something; everything here is additive, nothing is hidden.
Fiber *fiber.App
// Container holds the providers.
Container *di.Container
// Routes is the mounted route table.
Routes *router.Registry
// Health aggregates readiness checks.
Health *health.Registry
// Lifecycle holds init/ready/shutdown hooks.
Lifecycle *lifecycle.Registry
// Log is the application logger.
Log *slog.Logger
// contains filtered or unexported fields
}
Application is a configured, not-yet-listening service.
func New ¶
func New(opt Options) *Application
New builds the application. It does not listen; call Run.
func (*Application) API ¶
func (a *Application) API() fiber.Router
API returns the router every app is mounted on — the version prefix group. Use it for the rare route that belongs to no module.
func (*Application) Mount ¶
func (a *Application) Mount(descriptors ...module.Descriptor) error
Mount registers every domain's providers, then builds the domains, then mounts their routes — in that order, for every domain, not domain by domain.
Doing it domain by domain would construct the first before the second had registered anything, so a controller in the first that resolves a service from the second would fail at boot for no reason a reader could see.
func (*Application) MountApps ¶
func (a *Application) MountApps(apps ...module.App) error
MountApps mounts already-constructed domains.
Use it when the domains need no container — a test, or a service small enough to wire by hand. Everything else should use Mount, which gets the two phases right for you.
func (*Application) RouteTable ¶
func (a *Application) RouteTable() string
RouteTable renders the mounted routes, for a CLI or a boot-time dump.
func (*Application) RoutesJSON ¶
func (a *Application) RoutesJSON() ([]byte, error)
RoutesJSON renders the mounted route table as JSON, for `icpt routes`.
func (*Application) Run ¶
func (a *Application) Run(ctx context.Context) error
Run starts the listener and blocks until a signal arrives or the listener fails, then drains.
The sequence is deliberate and is the reason to use this rather than f.Listen directly: eager construction before the socket opens, so a bad dependency fails the deploy; the 404 handler added after every module, so a late-mounted route is not shadowed; lifecycle hooks around the listener; and a drain context that is NOT derived from the cancelled one.
func (*Application) Seed ¶
func (a *Application) Seed(ctx context.Context) error
Seed runs every module's Seeder. Call it after migrations, before Run.
func (*Application) Shutdown ¶
func (a *Application) Shutdown(ctx context.Context) error
Shutdown stops the listener and closes the container. Run does this for you; this is for an embedded or test-driven application.
func (*Application) WriteRoutes ¶
func (a *Application) WriteRoutes(path string) error
WriteRoutes writes the route table to a file.
Call it from a build step or behind a flag and commit the result: the dump is a diffable record of your public surface, so an accidentally added, removed or unguarded route shows up in code review rather than in production.
type Options ¶
type Options struct {
// Service is this service's name. Required.
Service string
// Version is the build version, reported on the health endpoints.
Version string
// Addr is the listen address, ":8080" by default.
Addr string
// Prefix is mounted in front of every app, e.g. "/api/v1". Empty mounts
// at the root, which is a choice you will regret the first time you need
// a v2 — set it.
Prefix string
// Logger defaults to a JSON logger at info level on stdout.
Logger *slog.Logger
// Fiber overrides the server config. ErrorHandler is set for you unless
// you provide one; overriding it opts out of the envelope and the leak
// check, so do it knowingly.
Fiber fiber.Config
// Middleware configures the standard chain.
Middleware middleware.ChainOptions
// CORS, when set, is installed before everything else.
CORS *middleware.CORSOptions
// RateLimit, when set, is installed after the identity middleware so its
// key function can see who is calling.
RateLimit *middleware.RateLimitOptions
// Filters are exception filters consulted before the built-in mapping.
Filters []filter.Filter
// Guards apply to every route of every mounted app.
Guards []guard.Guard
// Interceptors wrap every route of every mounted app.
Interceptors []interceptor.Interceptor
// Sanitizer scrubs outgoing messages. Install one in any service whose
// errors can carry infrastructure detail — which is all of them.
Sanitizer response.Sanitizer
// DrainTimeout bounds shutdown. Default 25s.
DrainTimeout time.Duration
// DisableHealthRoutes skips /healthz, /readyz and /health, for a service
// that publishes its own.
DisableHealthRoutes bool
// HealthPrefix moves the health endpoints. Default "" (service root), so
// they sit OUTSIDE the version prefix — a probe should not have to be
// updated when the API is versioned.
HealthPrefix string
}
Options configures the application.
Every field has a defensible zero value except Service: a service with no name produces logs nobody can route and metrics nobody can group.
Directories
¶
| Path | Synopsis |
|---|---|
|
cmd
|
|
|
icpt
command
Command icpt is the inceptools CLI: scaffolding, structure rules and SQL migrations, all driven by icpt.json.
|
Command icpt is the inceptools CLI: scaffolding, structure rules and SQL migrations, all driven by icpt.json. |
|
internal
|
|
|
lint
Package lint checks that a codebase follows the inceptools layering rules.
|
Package lint checks that a codebase follows the inceptools layering rules. |
|
migrate
Package migrate applies versioned SQL migrations, driven by icpt.json.
|
Package migrate applies versioned SQL migrations, driven by icpt.json. |
|
project
Package project loads icpt.json, the per-repository configuration for the icpt CLI.
|
Package project loads icpt.json, the per-repository configuration for the icpt CLI. |
|
scaffold
Package scaffold writes the files for a new module, app or service.
|
Package scaffold writes the files for a new module, app or service. |
|
src
|
|
|
core/config
Package config loads configuration from the environment into a struct, once, at boot — and fails the boot when something required is missing.
|
Package config loads configuration from the environment into a struct, once, at boot — and fails the boot when something required is missing. |
|
core/ctxkit
Package ctxkit carries request-scoped identity on a context.Context.
|
Package ctxkit carries request-scoped identity on a context.Context. |
|
core/di
Package di is the dependency-injection container: typed, lazy providers resolved through Go generics, with no reflection and no struct tags.
|
Package di is the dependency-injection container: typed, lazy providers resolved through Go generics, with no reflection and no struct tags. |
|
core/errs
Package errs is the single error vocabulary of an inceptools application.
|
Package errs is the single error vocabulary of an inceptools application. |
|
core/lifecycle
Package lifecycle gives a module three moments — init, ready, shutdown — and the signal handling that makes shutdown actually happen.
|
Package lifecycle gives a module three moments — init, ready, shutdown — and the signal handling that makes shutdown actually happen. |
|
core/logx
Package logx is the application logger: log/slog, with the request-scoped identity from ctxkit attached automatically.
|
Package logx is the application logger: log/slog, with the request-scoped identity from ctxkit attached automatically. |
|
core/module
Package module is the unit of organisation: a feature slice that declares what it provides, routes, owns and needs checked.
|
Package module is the unit of organisation: a feature slice that declares what it provides, routes, owns and needs checked. |
|
data/gormx
Package gormx translates database errors into the application's error vocabulary, and provides the query scopes every repository needs.
|
Package gormx translates database errors into the application's error vocabulary, and provides the query scopes every repository needs. |
|
data/repo
Package repo is a generic, tenant-scoped repository over GORM.
|
Package repo is a generic, tenant-scoped repository over GORM. |
|
platform/cache
Package cache is a small, typed caching layer with two implementations and one rule: a cache failure is never a request failure.
|
Package cache is a small, typed caching layer with two implementations and one rule: a cache failure is never a request failure. |
|
platform/events
Package events is a typed, in-process event bus: no `any` at the call site, no type assertion in the handler, and the failure modes handled.
|
Package events is a typed, in-process event bus: no `any` at the call site, no type assertion in the handler, and the failure modes handled. |
|
platform/lock
Package lock is mutual exclusion across processes: "only one replica runs this at a time".
|
Package lock is mutual exclusion across processes: "only one replica runs this at a time". |
|
platform/queue
Package queue provides a small lifecycle-aware in-process work queue.
|
Package queue provides a small lifecycle-aware in-process work queue. |
|
platform/scheduler
Package scheduler runs recurring work on a cron expression or a fixed interval, with the two properties that decide whether scheduled work is safe to deploy on more than one replica.
|
Package scheduler runs recurring work on a cron expression or a fixed interval, with the two properties that decide whether scheduled work is safe to deploy on more than one replica. |
|
reliability/breaker
Package breaker stops calling a dependency that is clearly down.
|
Package breaker stops calling a dependency that is clearly down. |
|
reliability/idempotency
Package idempotency makes a repeated POST safe.
|
Package idempotency makes a repeated POST safe. |
|
reliability/outbox
Package outbox makes a side effect as durable as the write that caused it.
|
Package outbox makes a side effect as durable as the write that caused it. |
|
reliability/retry
Package retry re-attempts work that failed for a reason that might not recur.
|
Package retry re-attempts work that failed for a reason that might not recur. |
|
testkit
Package testkit makes a module testable without a server, a port or a sleep.
|
Package testkit makes a module testable without a server, a port or a sleep. |
|
web/binding
Package binding turns a request into a validated DTO, or into an error that already knows how to render itself.
|
Package binding turns a request into a validated DTO, or into an error that already knows how to render itself. |
|
web/filter
Package filter is the last line of the request pipeline: it turns anything that escaped a handler into a response.
|
Package filter is the last line of the request pipeline: it turns anything that escaped a handler into a response. |
|
web/guard
Package guard is authorization: the question "may this caller do this?", asked once per route, before the handler runs.
|
Package guard is authorization: the question "may this caller do this?", asked once per route, before the handler runs. |
|
web/health
Package health answers the two questions an orchestrator asks, which are not the same question.
|
Package health answers the two questions an orchestrator asks, which are not the same question. |
|
web/interceptor
Package interceptor wraps a handler on both sides: before it runs, after it returns, and around a failure.
|
Package interceptor wraps a handler on both sides: before it runs, after it returns, and around a failure. |
|
web/middleware
Package middleware is the request-scoped plumbing every route needs before any handler runs: identity on the context, a trace id, a recovered panic, a deadline.
|
Package middleware is the request-scoped plumbing every route needs before any handler runs: identity on the context, a trace id, a recovered panic, a deadline. |
|
web/pagination
Package pagination reads list parameters off a request, with the bounds applied before anything reaches the database.
|
Package pagination reads list parameters off a request, with the bounds applied before anything reaches the database. |
|
web/pipe
Package pipe reads one value out of a request and converts it, returning an error that already carries the right status and the right field name.
|
Package pipe reads one value out of a request and converts it, returning an error that already carries the right status and the right field name. |
|
web/response
Package response is the single shape every HTTP response in an inceptools service takes, and the single place an outgoing message is scrubbed.
|
Package response is the single shape every HTTP response in an inceptools service takes, and the single place an outgoing message is scrubbed. |
|
web/router
Package router makes routes DATA.
|
Package router makes routes DATA. |
|
web/sse
Package sse exposes Fiber's SSE transport through the inceptools web layer.
|
Package sse exposes Fiber's SSE transport through the inceptools web layer. |
|
web/webhook
Package webhook contains transport-independent helpers for signed webhooks.
|
Package webhook contains transport-independent helpers for signed webhooks. |