Dependency Injection¶
dichit-backend uses Awilix with the @fastify/awilix Fastify plugin for all dependency wiring. This is how Clean Architecture stays clean at runtime (see architecture/dependency-flow.md).
How it works¶
makeAppregistersfastifyAwilixPlugin(composition root).makeInfrastructureDependencies()insrc/infrastructure/di.tsbuilds every concrete implementation and registers them withdiContainer.register(...).app.diContainer.cradleexposes the resolved graph to route handlers, services, and WebSocket handlers.- Tests can override resolvers via
makeApp(app, { dependencyOverrides }).
Patterns¶
Constructor injection (preferred for classes)¶
Cradle access (Fastify handlers)¶
app.get('/users', async (request, reply) => {
const listUsers = request.diScope.resolve('listUsersUseCase');
// or
const listUsers = app.diContainer.cradle.listUsersUseCase;
});
Contracts & implementations¶
flowchart LR
UC["Use case"] -->|"depends on"| I["interface (application/interfaces)"]
I -->|"implemented by"| IM["impl (infrastructure)"]
IM -->|"registered in"| DI["di.ts"]
DI -->|"resolved into"| C["Awilix cradle"]
C --> H["controllers / handlers / WS"] - Contracts live in
src/application/interfaces/**. - Implementations live in
src/infrastructure/**. di.tsis the only place that maps interface → implementation.
Adding a dependency¶
- Define (or reuse) the contract in
src/application/interfaces/.... - Implement it in
src/infrastructure/.... - Register it in
src/infrastructure/di.ts. - Inject it via constructor/cradle in the consumer.
- Add a unit test with a mock of the contract.
Testing¶
- Unit tests inject fakes/mocks of the contract — no real infra.
- Functional tests use
dependencyOverridesto swap cache/SMS/etc. (see testing.md).