Dependency Injection
Andurel applications use Fx for dependency injection and process lifecycle. Framework packages expose ordinary constructors; Fx belongs to the generated application in cmd/app, cmd/queue, and cmd/ssr.
Composition roots
Each process builds its own graph. Load validated environment before Fx, then provide only the collaborators that process should own:
1if err := config.LoadEnvironment(); err != nil {
2 fmt.Fprintln(os.Stderr, err)
3 os.Exit(1)
4}
5
6app := fx.New(
7 fx.Provide(func() context.Context { return ctx }),
8 config.Module,
9 databaseModule,
10 queueInsertModule,
11 models.Module,
12 controllers.Module,
13 cookies.Module,
14 router.Module,
15 fx.Invoke(startServer),
16)
Constructors return concrete types or small interfaces (storage.Connection, storage.InsertQueue, *inertia.Renderer, *kiks.Jar). Do not hide dependencies in Echo request context.
Publish the pool as both the interface and the concrete type when lifecycle needs Close:
1var databaseModule = fx.Module(
2 "database",
3 fx.Provide(fx.Annotate(
4 newDatabase,
5 fx.As(new(storage.Connection)),
6 fx.As(fx.Self()),
7 )),
8)
Application packages register focused modules. Generated models look like:
1var Module = fx.Module(
2 "models",
3 fx.Provide(
4 NewUsers,
5 NewTokens,
6 NewProducts,
7 ),
8)
Lifecycle
Register start/stop hooks for resources that must clean up: database pools, queue processors, SSR runtimes, and HTTP servers. A failed ping or constructor error should prevent process start.
1lc.Append(fx.Hook{
2 OnStart: func(ctx context.Context) error {
3 return db.Health(ctx)
4 },
5 OnStop: func(ctx context.Context) error {
6 return db.Close()
7 },
8})
Web needs HTTP and queue insertion. Queue needs a River processor and workers, but not the Echo server. Keep provider sets distinct so a process cannot accidentally acquire a capability it should not own.
Replacing implementations
Prefer the smallest public interface at the composition root. Tests can provide fake email senders or in-memory collaborators without rewriting controllers. Package updates should not silently introduce new environment contracts; environment mapping stays in application config/.
See Configuration, Request Lifecycle, and Framework Packages.