DI Container
Nova includes a built-in dependency injection container powered by Inversify. Register services in different scopes and inject them into controllers seamlessly.
The Di Class
The Di class wraps Inversify's Container and provides a clean API for registering services:
di.singleton(impl, abstraction?)
Registers a class as a singleton. The same instance is shared across all injections.
| Parameter | Type | Required | Description |
|---|---|---|---|
impl | Constructor<T> | Required | The implementation class. |
abstraction | AbstractConstructor<T> | Optional | Abstract class to bind to (for interface-based DI). |
di.transient(impl, abstraction?)
Creates a new instance every time the service is injected.
di.request(impl, abstraction?)
Creates one instance per request scope.
di.instance(token, value)
Binds a constant value to a token. Useful for configuration objects.
di.factory(token, factory)
Binds a factory function (resolved lazily as a singleton).
Registration Methods
1. Via app.register()
main.ts TypeScript
const app = await NovaFactory.create();
const di = app.register();
di.singleton(UserService);
di.transient(EmailService);
di.instance('CONFIG', { apiKey: 'abc123' });
di.factory('DB_CONNECTION', () => createConnection()); 2. Via Module
user.module.ts TypeScript
export const UserModule = new Module()
.registerController(UserController)
.registerSingleton(UserService)
.registerSingleton(PostgresUserRepo, IUserRepository); Interface-Based Injection
Use abstract classes as interfaces for clean DI:
user.repository.ts TypeScript
// Abstract interface
abstract class IUserRepository {
abstract findAll(): Promise<User[]>;
abstract findById(id: number): Promise<User | null>;
}
// Concrete implementation
class PostgresUserRepository extends IUserRepository {
async findAll() { return []; }
async findById(id: number) { return null; }
}
// Register
di.singleton(PostgresUserRepository, IUserRepository); Injecting Services
Use the @inject decorator from Inversify (re-exported by Nova):
user.controller.ts TypeScript
import { Controller, Get, inject } from '@abrahambass/nova';
@Controller('/users')
class UserController {
constructor(
@inject(IUserRepository) private repo: IUserRepository,
) {}
@Get()
async findAll() {
return this.repo.findAll();
}
} Optional Dependencies
Use @optional for dependencies that may not be registered:
Example TypeScript
import { inject, optional } from '@abrahambass/nova';
constructor(
@inject(CacheService) @optional() private cache?: CacheService,
) {}