Your application decides where settings come from; Arkoren components receive the values they need when you construct them. Required dependencies and settings are constructor arguments. Optional settings use a builder callback, a function that edits a temporary construction draft.
Keep environment and file formats in your application rather than decoding them into package-internal settings. This lets your deployment configuration stay stable as you change components or drivers.
Component Construction
With an existing HTTP handler named handler, construct a server using its
defaults. Import arkoren.dev/core/http/server:
listener := server.New(handler)
The handler is a required dependency. Construction does not bind a socket;
Start opens the listener. The generated project registers that startup and
cleanup in internal/bootstrap/server.go.
To select a loopback address, change only that setting during construction:
listener := server.New(handler, func(listener *server.Builder) {
listener.Addr("127.0.0.1:9090")
})
These are alternative constructions, not consecutive declarations. The callback
changes the address without replacing the server’s other defaults. Its parameter
is a *server.Builder, not a server you can reconfigure later. After construction,
changing a retained draft does not change the published component.
Required arguments can also be settings with no safe default, such as a validated signing key or a database connection string. Their validation and provisioning belong to the relevant key or driver guide, not an optional callback.
Preserving Defaults
Omit settings you do not need to change. For example, the server’s default header
read timeout is 10 seconds; changing its address leaves that timeout in place.
Its default address is :8080, which listens on all interfaces, not only loopback.
Defaults are not a substitute for application security policy.
Zero and empty values are package-specific. The server restores its default for an empty address or zero timeout. Its negative write timeout disables the write deadline; that exception is useful for streaming but should not be applied to ordinary endpoints without a reason. Other builders can treat an empty value as an explicit instruction to disable or clear a setting.
Do not copy every documented default into your callback or assume every collection setting appends. Check the particular method’s contract when replacing lists, clearing values, or disabling protection.
Shared Policies
When several listeners need the same header deadline, give that construction
policy a typed name. Import time for the duration:
headers := server.BuilderFunc(func(listener *server.Builder) {
listener.ReadHeaderTimeout(5 * time.Second)
})
Apply the policy, then add the settings specific to this listener:
listener := server.New(handler, headers, func(listener *server.Builder) {
listener.Addr("127.0.0.1:9090")
})
Callbacks run once, synchronously, in argument order on one fresh draft. A later
scalar setting replaces an earlier one. server.BuilderFunc is an alias for the
ordinary callback type, so it also works in slices passed with policies....
Use the alias belonging to the constructor’s role; a server policy cannot configure
a cache or queue consumer.
To omit optional policies, omit arguments or expand an empty slice. Supplying a nil callback panics; it does not mean “use defaults.” Do not mutate the draft concurrently with construction.
Environment Settings
Read values beside the code that constructs their consumer. In the generated
internal/bootstrap/server.go, the existing factory callback imports os and
constructs its listener with:
listener := server.New(handler, func(listener *server.Builder) {
listener.Addr(os.Getenv("HTTP_ADDR"))
})
The factory reads HTTP_ADDR when composition invokes its callback, not when
Server(handler) returns the factory. Empty or unset values preserve :8080.
Later environment changes do not reconfigure that listener.
Core packages do not load your application environment or files. The starter’s
executable separately imports godotenv/autoload, which reads .env during
initialization without overriding process environment values. Its loading errors
are ignored, so validate required settings explicitly rather than treating a
present .env as proof of valid configuration.
For example, if you add a required service credential, reject a missing value in
your application’s loader before constructing the client. In a function returning
an error, with errors and os imported:
token := os.Getenv("REPORTS_TOKEN")
if token == "" {
return errors.New("REPORTS_TOKEN is required")
}
Do not log the token or include it in the error. This validation establishes presence, not authorization or remote reachability. A driver’s documented startup or first operation establishes those later conditions.
Typed Settings
Extract a loader when several components share values or parsing becomes
substantial. Keep its result application-owned. For example, a server loader
could return this type from your own internal/settings package:
type HTTP struct {
Addr string
ShutdownTimeout time.Duration
}
Import time in that package. Begin with a zero ShutdownTimeout, preserving the
server’s default, and parse an override only when it is present. Inside a loader
returning (HTTP, error), use errors, os, and time:
cfg := HTTP{Addr: os.Getenv("HTTP_ADDR")}
if value := os.Getenv("HTTP_SHUTDOWN_TIMEOUT"); value != "" {
timeout, err := time.ParseDuration(value)
if err != nil || timeout <= 0 {
return HTTP{}, errors.New("HTTP_SHUTDOWN_TIMEOUT must be a positive duration")
}
cfg.ShutdownTimeout = timeout
}
This application policy permits positive overrides such as 20s; it rejects
malformed, zero, or negative input rather than silently changing shutdown behavior.
Return cfg, nil after any other application checks. The fragments show the
loader’s type and parsing branch, not a complete loader implementation.
After checking the loader’s error, translate its result into component settings where you construct the server:
listener := server.New(handler, func(listener *server.Builder) {
listener.Addr(cfg.Addr)
listener.ShutdownTimeout(cfg.ShutdownTimeout)
})
An absent override leaves the server’s 15-second drain default intact. Keep your
JSON/YAML schema or environment variable names on HTTP and its loader, not on
an Arkoren reporting snapshot. Components that expose Config() do not thereby
accept that record as constructor input.
Validation Boundaries
Check each constructor’s contract rather than assuming every mistake becomes a returned error at construction. Some constructors return configuration errors; some middleware constructors panic for invalid code-authored policy; reusable definitions can retain domain errors until registration or use. Network and TLS failures can appear during startup. A successful constructor does not establish that a backend is reachable.
Publication separates owned settings from the temporary draft, not every object
reachable from it. Clients, service pointers, functions, captures, and native TLS
configuration can remain shared. Finish their setup before concurrent use.
Before wrapping a native client with NewFrom, read the driver’s ownership rules:
wrapping does not necessarily mean borrowing, and Stop can close that client.
For startup and cleanup ownership, continue with
Lifecycle and Ownership. The
server API reference
documents the defaults and builder methods used here.