Documentation
¶
Overview ¶
Package di is a dependency-injection container for Go 1.27+ built on generic methods.
Services are registered on a Scope and resolved from it by type:
app := di.New()
app.Value(Config{DSN: "postgres://localhost/app"})
app.Provide(func(s *di.Scope) *DB { return s.Must(sql.Open("postgres", s.Get[Config]().DSN)) }).
OnStop(func(ctx context.Context, db *DB) error { return db.Close() })
app.Provide(func(s *di.Scope) *Repo { return &Repo{db: s.Get[*DB]()} })
repo, err := app.Resolve[*Repo]()
Keys are Go types, so there is no naming scheme and no collisions between packages. Constructors return T rather than (T, error): inside a constructor, Scope.Get and Scope.Must abort on failure and the error surfaces from the enclosing Scope.Resolve, Scope.Start or Scope.Run with the dependency path and the registration site.
Lifetimes ¶
A binding is a singleton by default, cached in the scope that registered it. Binding.Scoped makes it one instance per resolving scope, built there so it can see that scope's values, which is how request-scoped services are declared once in the root. Binding.Group and Scope.All handle groups, and Scope.Maybe resolves optional dependencies. An interface is served by a constructor that returns the implementation: s.Provide(func(s *Scope) Reader { return s.Get[*Repo]() }).
Scopes ¶
Scope.Child creates a scope that resolves through its parent, reuses the parent's singletons and owns the lifecycle of what it builds. A child may shadow a key its parent provides; within one scope, a second registration of a key must be marked Binding.Override, or the next resolution rejects it naming both sites. That marker is the test seam: wire the production graph into a fresh scope, then override what you want faked before anything is resolved (Test does the bookkeeping). For HTTP, github.com/floatdrop/di/dihttp.Middleware gives each request a child scope holding the *http.Request, reachable through FromContext.
Modules ¶
A Module is a function that registers into a scope, and Scope.Use applies modules in order. Registrations are attributed to the module that made them, so a collision between two modules is reported as one: "*app.DB is provided at storage (wire.go:12) and again at caching (cache.go:8)".
Lifecycle ¶
Binding.OnStart, Binding.OnDrain and Binding.OnStop are typed hooks. Scope.Start builds Binding.Eager bindings and runs start hooks in build order, rolling back on failure; services built later start as part of being built. Scope.Stop first drains, which lets work already in flight finish while the scope still resolves, then stops child scopes, then services in reverse build order, and afterwards the scope refuses to resolve anything. Binding.Worker runs a long-lived function that is cancelled on stop. Scope.Run ties it together for a main function: start, wait for a signal or Scope.Shutdown, stop with a deadline. Scope.Observe reports every step for logging and metrics.
Inspecting the graph ¶
A constructor's dependencies are recorded as it resolves them, so the graph is known for whatever has been built. Scope.Explain renders one service's dependency tree, with the registration site, lifetime and scope of each node, and what needed it. Scope.Graph renders everything built in a scope and its descendants as Graphviz DOT.
Concurrency ¶
A Scope is safe to use from many goroutines, including from goroutines a constructor starts for itself: the resolution path is immutable, so branches that run in parallel share nothing. A constructor may also keep the Scope it was handed and resolve through it later, once its own service is built; the finished part of that path is no longer a dependency, so such a resolution is not a cycle. A service is built once however many resolutions race for it, and a resolution of a running scope returns only a service whose start step has finished. A cycle is reported as ErrCycle even when the two halves are being built concurrently.
Three re-entrancy limits apply. A goroutine started by a constructor must use Scope.Resolve rather than Scope.Get, because Get reports failure by panicking and that panic cannot unwind to the enclosing call from another goroutine. An Binding.OnStart hook must not resolve a service that depends on the one being started: the hook already holds the value, and waiting for itself cannot make progress. And no hook may call Scope.Stop on its own scope or an ancestor, because Stop waits for the very step the hook is running; call Scope.Shutdown, which never blocks.
Example ¶
package main
import (
"context"
"fmt"
"github.com/floatdrop/di"
)
type Server struct{ repo *Repo }
func main() {
app := di.New()
app.Value(Config{DSN: "pg://primary"})
app.Provide(func(s *di.Scope) *DB { return &DB{dsn: s.Get[Config]().DSN} }).
OnStop(func(ctx context.Context, db *DB) error { fmt.Println("close", db.dsn); return nil })
app.Provide(func(s *di.Scope) *Repo { return &Repo{db: s.Get[*DB]()} })
app.Provide(func(s *di.Scope) Reader { return s.Get[*Repo]() })
app.Provide(func(s *di.Scope) *Server { return &Server{repo: s.Get[*Repo]()} }).Eager().
OnStart(func(context.Context, *Server) error { fmt.Println("listening"); return nil }).
OnStop(func(context.Context, *Server) error { fmt.Println("stopped"); return nil })
if err := app.Start(context.Background()); err != nil {
panic(err)
}
fmt.Println("read:", app.Get[Reader]().Read())
_ = app.Stop(context.Background())
}
Output: listening read: pg://primary stopped close pg://primary
Index ¶
- Variables
- func WithScope(ctx context.Context, s *Scope) context.Context
- type Binding
- func (b Binding[T]) Eager() Binding[T]
- func (b Binding[T]) Group() Binding[T]
- func (b Binding[T]) OnDrain(f func(context.Context, T) error) Binding[T]
- func (b Binding[T]) OnStart(f func(context.Context, T) error) Binding[T]
- func (b Binding[T]) OnStop(f func(context.Context, T) error) Binding[T]
- func (b Binding[T]) Override() Binding[T]
- func (b Binding[T]) Scoped() Binding[T]
- func (b Binding[T]) Worker(f func(context.Context, T) error) Binding[T]
- type Event
- type EventKind
- type Module
- type RunOption
- type Scope
- func (s *Scope) All[T any]() []T
- func (s *Scope) Child(name string) *Scope
- func (s *Scope) Context() context.Context
- func (s *Scope) Explain[T any]() string
- func (s *Scope) Get[T any]() T
- func (s *Scope) Graph() string
- func (s *Scope) Maybe[T any]() (T, bool)
- func (s *Scope) Modules() string
- func (s *Scope) Must[T any](v T, err error) T
- func (s *Scope) Observe(fn func(Event))
- func (s *Scope) Provide[T any](ctor func(*Scope) T) Binding[T]
- func (s *Scope) Resolve[T any]() (v T, err error)
- func (s *Scope) Run(ctx context.Context, opts ...RunOption) error
- func (s *Scope) Shutdown(cause error)
- func (s *Scope) Start(ctx context.Context) error
- func (s *Scope) Stop(ctx context.Context) error
- func (s *Scope) Use(mods ...Module)
- func (s *Scope) Validate(stubs ...Stub) Validation
- func (s *Scope) Value[T any](v T) Binding[T]
- func (s *Scope) Wire[T any](ctor any) Binding[T]
- func (s *Scope) Wrap[T any](fn any) Binding[T]
- type Stub
- type TB
- type Validation
Examples ¶
Constants ¶
This section is empty.
Variables ¶
Functions ¶
Types ¶
type Binding ¶
type Binding[T any] struct { // contains filtered or unexported fields }
Binding is the typed handle returned by Provide/Value. Its methods refine the registration; they must be called before the first resolution from this scope.
func (Binding[T]) Eager ¶
Eager builds the service during Start rather than on first use.
Eagerness belongs to the key, not the registration: it means the service exists by the time Start returns. Overriding an eager binding therefore keeps the key eager and builds the replacement; a replacement with a per-scope lifetime, which cannot be built once at Start, is rejected.
func (Binding[T]) Group ¶ added in v0.7.0
Group makes the binding a member of the multi-binding group for T instead of the binding for T: it neither shadows nor is shadowed by another registration of T, and the members are read back together with s.All[T](). A member keeps its own lifetime and hooks.
func (Binding[T]) OnDrain ¶ added in v0.4.0
OnDrain runs before anything is stopped: Stop drains the whole tree, from the innermost scope outwards and in reverse build order, while every scope still resolves normally. It is where a service stops accepting new work and waits for the work it already has, such as an HTTP server that must finish in-flight requests whose handlers still need their request scope. Anything those handlers build, including a request scope of their own, is drained before the phase ends. Use OnStop for the release that follows.
func (Binding[T]) OnStart ¶
Typed lifecycle hooks: no interface sniffing, no reflection.
OnStart runs once the service is built, and only a hook that returns normally starts it: one that panics fails the start step, like a panicking constructor, and the service is never served.
func (Binding[T]) Override ¶ added in v0.8.0
Override declares that this registration replaces an earlier one of the same key in the same scope. Without it a second registration of a key is rejected at the next resolution, naming both sites, because a duplicate that wins silently is how one module reroutes another module's wiring without anyone noticing. With it the later registration serves the key, and inherits its eagerness, which is the test seam:
s := di.Test(t, app.Production)
s.Value(&DB{DSN: "sqlite://memory"}).Override()
There must be something to override in this scope, or that is rejected too: a fake for a service that has since been renamed would otherwise be a registration nobody resolves, and the test would pass against production wiring. A child scope shadows its parent without Override, since that is a different registry rather than a replacement. A key that has already served a value cannot be overridden at all.
func (Binding[T]) Scoped ¶
Scoped makes the binding one-per-scope: each scope that resolves it gets its own instance, built in that scope (so it can see that scope's values) and stopped with it. Declare request-scoped services once in the root and resolve them through the request scope.
Example ¶
package main
import (
"context"
"fmt"
"github.com/floatdrop/di"
)
type Session struct{ ID string }
func main() {
app := di.New()
// Declared once in the root, built once per scope that resolves it.
app.Provide(func(s *di.Scope) *Session { return &Session{ID: s.Get[string]()} }).Scoped()
for _, id := range []string{"a1", "b2"} {
req := app.Child("request")
req.Value(id)
first, again := req.Get[*Session](), req.Get[*Session]()
fmt.Println(first.ID, first == again)
_ = req.Stop(context.Background())
}
}
Output: a1 true b2 true
func (Binding[T]) Worker ¶ added in v0.7.0
Worker registers a long-running function for T, such as a consumer loop. It is started in its own goroutine once the service starts and its context is cancelled when the service stops; Stop waits for it to return, bounded by its own context. A hook that outlasts that deadline is reported by Stop, and OnStop then waits for it rather than releasing the value underneath a worker still reading it.
Returning a non-nil error calls Shutdown with it, stopping the application, even if the scope was already stopping: a worker may fail, flush while the scope winds down, and only then report. The exception is context.Canceled from a hook that was already cancelled, which is a worker reporting the cancellation and nothing else. A hook that wants to stay quiet during shutdown should return nil.
Example ¶
package main
import (
"context"
"fmt"
"github.com/floatdrop/di"
)
type Queue struct{ jobs chan string }
func main() {
app := di.New()
done := make(chan string, 1)
app.Provide(func(*di.Scope) *Queue { return &Queue{jobs: make(chan string, 1)} }).Eager().
Worker(func(ctx context.Context, q *Queue) error {
for {
select {
case job := <-q.jobs:
done <- "processed " + job
case <-ctx.Done():
return nil // cancelled by Stop
}
}
})
ctx := context.Background()
if err := app.Start(ctx); err != nil {
panic(err)
}
app.Get[*Queue]().jobs <- "email"
fmt.Println(<-done)
fmt.Println("stop:", app.Stop(ctx)) // waits for the worker to return
}
Output: processed email stop: <nil>
type Event ¶
type Event struct {
Kind EventKind
Service string // the service, e.g. "*github.com/acme/app.DB"; empty for shutdown
Scope string // name of the scope that owns the instance
Site string // file:line of the registration; empty for shutdown
Module string // the Module the service was registered from; empty when none
Duration time.Duration
Err error
}
Event describes one lifecycle step. Observers receive it after the step completes, with its duration and error if any.
type EventKind ¶
type EventKind string
EventKind classifies an Event.
const ( EventBuild EventKind = "build" // a constructor ran EventStart EventKind = "start" // an OnStart hook ran EventDrain EventKind = "drain" // an OnDrain hook ran EventStop EventKind = "stop" // a Worker hook was cancelled and/or an OnStop hook ran EventShutdown EventKind = "shutdown" // Shutdown was called )
type Module ¶ added in v0.8.0
type Module func(*Scope)
A Module is a unit of wiring: a function that registers into a scope. Modules compose by ordinary function composition, and Scope.Use applies them in order. Every registration a module makes is attributed to it, so a collision between two modules is reported as one.
type RunOption ¶
type RunOption func(*runConfig)
RunOption configures Run.
func StopTimeout ¶
StopTimeout bounds how long Stop may take once Run decides to exit. The default is 15 seconds.
type Scope ¶
type Scope struct {
// contains filtered or unexported fields
}
Scope is a container. A Scope value handed to a constructor is a view over the same state that carries the current resolution path.
func FromContext ¶
FromContext returns the scope attached with WithScope, if any.
func Test ¶ added in v0.2.0
Test returns a scope for a test: the modules register the graph under test, and the scope is stopped when the test ends, failing it if a stop hook errors. Override what you need faked after wiring and before resolving, saying so:
s := di.Test(t, app.Production)
s.Value(&DB{DSN: "sqlite://memory"}).Override()
repo := s.Get[*Repo]()
func (*Scope) All ¶
All resolves the multi-binding group for T across the scope chain. Members are singletons (or Scoped if so marked) with the same lifecycle as any other binding.
func (*Scope) Child ¶
Child creates a scope that resolves through s. Stopping s stops its children first.
A child made inside a constructor carries that constructor's resolution path, so a cycle through it is reported rather than deadlocking. The path goes inert when the constructor returns (see resolver.done), so a child kept for later, such as a request scope, resolves as an independent branch.
func (*Scope) Context ¶
Context returns the context passed to Start (or Run) on this scope or the nearest started ancestor, so constructors can dial with a deadline. Before Start it returns context.Background().
func (*Scope) Explain ¶ added in v0.8.0
Explain renders what T resolves to and what it was built from: the dependency tree, each node with its lifetime, its scope, the state of its lifecycle and where it was registered, followed by what needed it.
What has been built has a recorded tree, because a constructor's dependencies are recorded as it resolves them. A service that has not been built is reported as such, with its registration; if it was registered with Wire, the dependencies it declares are drawn under it with dashed edges, each continuing as a recorded tree where it has been built and as a declared one where it has not, and "declared by" lists the unbuilt services that declare it. A closure that has not run ends its branch, since nothing is known about it yet, and so does a key nothing provides. Explain resolves nothing and builds nothing; it commits pending registrations the way a resolution from this scope would, so a configuration this scope would reject is reported here by the same panic.
A key served by a group is explained member by member. A dependency reached twice, as in a diamond, is expanded once and named on later visits, so the tree stays finite and the repeat is visibly the same instance.
func (*Scope) Get ¶
Get resolves T. Inside a constructor, failure unwinds to the enclosing Resolve/Start call and becomes an error; at top level it panics. In a goroutine a constructor started, use Resolve instead: that panic has no enclosing call to unwind to and would take the process down.
func (*Scope) Graph ¶ added in v0.8.0
Graph renders everything built in this scope and its descendants as Graphviz DOT: one box per instance, one cluster per scope that holds any, and an arrow from each instance to what its constructor resolved.
It reads the graph and changes nothing, not even the pending registrations, so it is safe to call from a handler or a hook. Nodes are numbered in the order the scopes were created and the instances were built, so the same run of the same program renders the same document. A scope that has been stopped no longer holds its instances and contributes nothing.
The detail is deliberately thin -- a registration site would not fit in a box. Use Explain for one service in full.
func (*Scope) Modules ¶ added in v0.14.0
Modules renders the modules registered into this scope and its ancestors: what each provides, what it needs and which module serves it, what it wraps, and which of its constructors are closures whose needs are unknown until they run. A need only a resolving scope can provide, as a request scope provides the request, is reported as owed, the way Validate reports it. A dependency a module serves for itself is not a module dependency and is left out. Registrations made outside any module are grouped as "registered directly".
Like Explain, it builds nothing and commits pending registrations the way a resolution would, so a configuration this scope would reject is reported by the same panic.
func (*Scope) Must ¶
Must unwraps a (value, error) pair inside a constructor:
db := s.Must(sql.Open("postgres", dsn))
A non-nil error aborts the constructor and surfaces from the enclosing Resolve, Start or Run. Outside a constructor it panics with the error.
func (*Scope) Observe ¶
Observe registers fn to receive lifecycle events from this scope and every scope under it. Use it for logging and metrics.
Example ¶
package main
import (
"context"
"errors"
"fmt"
"github.com/floatdrop/di"
)
type Cache struct{}
func main() {
app := di.New()
app.Observe(func(ev di.Event) {
fmt.Println(ev.Kind, ev.Service, ev.Err)
})
app.Provide(func(*di.Scope) *Cache { return &Cache{} }).
OnStop(func(context.Context, *Cache) error { return errors.New("flush failed") })
app.Get[*Cache]()
_ = app.Stop(context.Background())
}
Output: build *github.com/floatdrop/di_test.Cache <nil> stop *github.com/floatdrop/di_test.Cache di: stopping *github.com/floatdrop/di_test.Cache: flush failed
func (*Scope) Provide ¶
Provide registers a lazily built singleton. T is inferred from the constructor's return type; dependencies are pulled with s.Get[...]().
func (*Scope) Run ¶
Run starts the scope and blocks until ctx is cancelled, a termination signal arrives, or Shutdown is called. It then stops the scope with a bounded context; a second signal during the stop cancels that context so a hung hook cannot keep the process alive. Run returns the Start error, the error passed to Shutdown, and any Stop errors, joined. A worker that died on its own is reported once, whether it reached Run as the cause or as a Stop error.
func (*Scope) Shutdown ¶
Shutdown asks a running Run to stop and records the cause it should return. It never blocks, may be called from any goroutine, and the first call wins. It propagates to ancestor scopes, so a service in a child scope can stop the application.
func (*Scope) Start ¶
Start builds every Eager binding in registration order, then runs the start step of everything built so far, in build order. If a constructor or a start step fails, the scope is stopped, which rolls back exactly the services that did start, child scopes included. A service that was built but never started is not stopped, so acquire resources in OnStart rather than in the constructor when the binding declares one.
After Start returns, a service built later runs its start step as part of being built, so lazily resolved services start too. Start may be called once, and builds only this scope's own Eager bindings: a child scope's are built by that child's Start.
func (*Scope) Stop ¶
Stop winds the scope down in three phases. First it drains: OnDrain hooks run from the innermost scope outwards, in reverse build order, while every scope still resolves, so work already in flight can finish and still reach its dependencies. A service or child scope that phase brings into being is drained too, before anything is marked stopped. Then the scope is marked stopped and child scopes are stopped. Then OnStop hooks run in reverse build order (dependents first).
A service is stopped only if it started, or if it declares no OnStart, in which case OnStop is a plain destructor. Every failure is reported.
Stop is synchronous. It waits out whatever another goroutine is still running for a service it is tearing down -- a start step in flight, a drain hook another Stop began, a Worker hook being cancelled -- so when it returns, the teardown has happened and its failures are in the error. A teardown outlives the call in one case, when ctx expires first: the missed deadline is reported here, and the release is finished once the outstanding step returns, on a goroutine of its own, reaching observers rather than this caller. A constructor that finishes after the scope has stopped is likewise undone by whichever goroutine was resolving it.
Afterwards the scope and its descendants refuse to resolve anything, with ErrStopped; that includes a resolution that was already waiting when the scope stopped, so a closed service is never handed out. Stopping a child scope also detaches it from its parent, so per-request scopes are released once stopped.
Stop is idempotent, and concurrent calls are safe: only the first tears the scope down, and the others wait for it and report its result, bounded by their own context. Two Stop calls that meet at one scope, as a child and its parent do, wait for each other phase by phase, so neither starts releasing what the other's hooks are still using.
Because Stop waits, a hook must not call Stop on its own scope or an ancestor: it would be waiting for the step it is itself running. Stopping a sibling, or a scope below the hook's own, is allowed. A hook that passes on the context it was given gets an error saying so; one that passes a context of its own is not recognised, and waits until that context expires. Call Shutdown, which never blocks.
func (*Scope) Use ¶ added in v0.8.0
Use applies each module to this scope. A registration made while a module runs -- directly, or from a child the module opens, or later from a constructor the module registered -- carries that module's name, which is the name of the function: register modules as named functions rather than closures, or the name is the enclosing function's.
func (*Scope) Validate ¶ added in v0.9.0
func (s *Scope) Validate(stubs ...Stub) Validation
Validate checks the wiring visible from this scope without building anything. A singleton is checked against the scope that registered it, since that is where it is built. A Scoped binding is checked as if resolved from this scope, and what this scope does not provide for it is reported as Owed rather than as an error, because a descendant may:
v := app.Validate() // *http.Request is owed to a request scope
The stubs say what such a descendant will hold, so that the check can be made from the application scope as that descendant would make it. With stubs the caller has described the resolving scope, and a dependency neither this scope nor the stubs provide is an error:
err := app.Validate(di.Provided[*http.Request]()).Err()
Like Explain, Validate commits pending registrations the way a resolution would, so a configuration this scope would reject is reported by the same panic.
func (*Scope) Wire ¶ added in v0.9.0
Wire registers a lazily built singleton from a constructor of any arity, whose parameters are its dependencies:
s.Wire[*Server](NewServer) // func NewServer(cfg Config, repo *Repo) *Server
ctor must be a non-variadic function returning T, or T and an error, and is read with reflection once, here. Each parameter type is resolved from the same scope view a Provide closure would see, so lifetimes, cycles, hooks and error paths are unchanged; what Wire adds is that the dependencies are known at registration, before anything is built. A non-nil error from ctor aborts the build exactly as s.Must does.
T cannot be inferred from an untyped argument, so it is spelled out, and a constructor whose result is not assignable to T is rejected here, with the other configuration errors. A concrete constructor may therefore serve an interface key directly: s.Wire[Repository](NewPGRepo). The build calls ctor through reflect, which costs about 150ns and two allocations per build over a Provide closure; a warm Get is the same code for both.
func (*Scope) Wrap ¶ added in v0.10.0
Wrap registers a wrapper over the registration that serves T when Wrap is called: the latest one in this scope, or the one an ancestor provides. fn takes the value being wrapped first and its other dependencies after it, read with reflection as Wire reads a constructor, and returns T, or T and an error:
s.Wrap[Store](func(next Store, c *Cache) Store { return &caching{next, c} })
What is wrapped keeps its registration, hooks and lifetime: it is built first, as the wrapper's dependency, and so stopped after it. The wrapper serves T from this scope down. In a child scope it wraps the parent's value for that child and its descendants and leaves the parent and its other children as they were, which is what uber/fx calls Decorate. Wrappers chain in registration order, and a wrapper takes the lifetime of what it wraps; Scoped() on the wrapper makes it one per resolving scope over a shared inner value. An Override registered afterwards replaces the wrapper and everything it wrapped. Nothing to wrap is rejected here, and a group cannot be wrapped: its members are read with All. A key this scope has already resolved is rejected at the next resolution, as an Override is, since callers already hold the unwrapped value.
type Stub ¶ added in v0.11.0
type Stub struct {
// contains filtered or unexported fields
}
Stub names a key the scope resolving a Scoped binding will provide, for Validate to take as given. Make one with Provided.
type Validation ¶ added in v0.9.0
type Validation struct {
// Errors are the failures the declared graph proves: a dependency nothing
// provides, a cycle among Wire constructors, or a singleton that would
// build a Scoped service in its own scope, where that service's
// dependencies are not provided. Each wraps ErrNotProvided or ErrCycle.
Errors []error
// Owed lists the dependencies of Scoped bindings that this scope does not
// provide. A Scoped service is built in the scope that resolves it, so
// these are left to that scope: call Validate from there, or say what it
// will hold with Provided stubs, and they are checked as errors instead.
Owed []string
// Unchecked lists the Provide constructors in the chain, whose
// dependencies are known only once they run.
Unchecked []string
}
Validation is what Validate found.
func (Validation) Err ¶ added in v0.9.0
func (v Validation) Err() error
Err joins Errors, or is nil when the declared graph proves no failure.
Directories
¶
| Path | Synopsis |
|---|---|
|
Package dihttp connects a di.Scope to net/http.
|
Package dihttp connects a di.Scope to net/http. |
|
examples
|
|
|
app
command
A complete service: request scopes through middleware, a background worker with a Worker hook, a health endpoint, and graceful shutdown.
|
A complete service: request scopes through middleware, a background worker with a Worker hook, a health endpoint, and graceful shutdown. |
|
explain
command
Inspecting the graph: what a service was built from, and what needed it.
|
Inspecting the graph: what a service was built from, and what needed it. |
|
guide/cmd/api
command
Command api is the application: it composes the modules, checks the graph, and runs until a signal arrives.
|
Command api is the application: it composes the modules, checks the graph, and runs until a signal arrives. |
|
guide/internal/api
Package api serves HTTP.
|
Package api serves HTTP. |
|
guide/internal/cache
Package cache puts a cache in front of the store.
|
Package cache puts a cache in front of the store. |
|
guide/internal/config
Package config reads the settings the application starts with.
|
Package config reads the settings the application starts with. |
|
guide/internal/mail
Package mail sends messages from a background worker.
|
Package mail sends messages from a background worker. |
|
guide/internal/storage
Package storage owns the database connection and the store built on it.
|
Package storage owns the database connection and the store built on it. |
|
instances
command
More than one instance of a type: a defined type names each one while the set is fixed, and a Scoped selector picks one when the set comes from configuration.
|
More than one instance of a type: a defined type names each one while the set is fixed, and a Scoped selector picks one when the set comes from configuration. |
|
quickstart
command
Quick start: register a few services, start and stop the application.
|
Quick start: register a few services, start and stop the application. |
|
scopes
command
Scopes: a child scope sees everything in its parent and can shadow it.
|
Scopes: a child scope sees everything in its parent and can shadow it. |
|
server
command
Graceful shutdown of an HTTP server.
|
Graceful shutdown of an HTTP server. |
|
testing
Package app shows how to substitute dependencies in tests: wire the production graph into a fresh scope, then override before resolving.
|
Package app shows how to substitute dependencies in tests: wire the production graph into a fresh scope, then override before resolving. |
|
wire
command
Wire: plain constructors whose parameters are their dependencies, and a graph that is checked before anything is built.
|
Wire: plain constructors whose parameters are their dependencies, and a graph that is checked before anything is built. |
|
wrap
command
Wrap: compose over a service without replacing it.
|
Wrap: compose over a service without replacing it. |