Guide
Dependency Injection
LaraNode uses a powerful IoC (Inversion of Control) container for dependency injection, inspired by Laravel's container.
Dependency Injection
LaraNode uses a powerful IoC (Inversion of Control) container for dependency injection, inspired by Laravel's container.
The Container
The container is the heart of LaraNode's dependency injection system:
import { container, Container } from "@lara-node/core";
// Get the singleton instance
const container = container;
// Or create your own
const myContainer = new Container();
Binding Services
Simple Binding
container.bind("logger", () => new Logger());
const logger = container.make("logger");
Singleton Binding
Singletons are resolved once and cached:
container.singleton(DatabaseService, () => {
return new DatabaseService(config("database"));
});
// Same instance returned each time
const db1 = container.make(DatabaseService);
const db2 = container.make(DatabaseService);
// db1 === db2
Instance Binding
Bind an existing instance:
const expressApp = express();
container.instance("express", expressApp);
Alias Binding
Create aliases for existing bindings:
container.bind("cache", () => new CacheManager());
container.alias("cache", CacheManager);
// Both resolve to the same service
container.make("cache");
container.make(CacheManager);
Resolving Services
Using make()
const service = container.make(UserService);
Using app() Helper
import { app } from "@lara-node/core";
// Resolve a service
const service = app(UserService);
// Get the container
const container = app();
Automatic Resolution
The container can automatically resolve class dependencies:
import { Injectable } from "@lara-node/core";
@Injectable()
class EmailService {
constructor(private mailer: MailManager) {}
sendWelcomeEmail(user: User) {
this.mailer.to(user.email).send();
}
}
// Container automatically resolves MailManager
const emailService = container.make(EmailService);
Injectable Decorator
Mark classes for automatic dependency injection:
import { Injectable } from "@lara-node/core";
@Injectable()
class UserService {
constructor(
private db: DatabaseService,
private cache: CacheManager,
private events: EventDispatcher,
) {}
}
Resolving Callbacks
Run callbacks when a type is resolved:
container.resolving(UserService, (service) => {
service.initialize();
});
Binding Contextual Values
Bind different implementations based on context:
container
.when(DatabaseService)
.needs(CacheDriver)
.give(() => new RedisCache());
Practical Example
// src/app/Providers/AppServiceProvider.ts
import { ServiceProvider } from "@lara-node/core";
import { UserService } from "../Services/UserService";
import { AuthService } from "../Services/AuthService";
export class AppServiceProvider extends ServiceProvider {
register() {
// Bind services
this.app.singleton(UserService, () => {
return new UserService(this.app.make(DatabaseService), this.app.make(CacheManager));
});
this.app.singleton(AuthService, () => {
return new AuthService(this.app.make(UserService), this.app.make(JwtService));
});
}
}
// Usage in controller
import { Injectable } from "@lara-node/core";
@Injectable()
class UserController {
constructor(private userService: UserService) {}
async index() {
return this.userService.all();
}
}
Next Steps
- Service Providers -- Learn about service providers
- Core Container -- Deep dive into the container
- Application -- Learn about the Application class