@leandromatos/provider-manager
v0.0.0-snapshot.20250306.1
Published
Provider Manager
Readme
Provider Manager 📦
Provider Manager is a lightweight dependency injection container designed to manage class constructors and factory functions. It allows you to register and resolve dependencies easily and supports both class-based providers and factory-based providers, giving you flexibility in how you handle your dependencies.
Installation
Install the package using yarn or any other package manager:
yarn add @leandromatos/provider-managerFeatures
- Register providers using class constructors or factory functions.
- Resolve dependencies using string identifiers or directly via class constructors or factory functions.
- Automatic dependency resolution with
@Inject. - Simple and intuitive API for managing dependencies.
Decorators
@Injectable
The @Injectable decorator marks a class or factory function as a provider that can be managed by the ProviderManager. Without this decorator, the ProviderManager will not be able to handle the class or factory.
@Injectable()
class Logger {
log(message: string): void {
console.log(`[LOG]: ${message}`)
}
}In this example, Logger is marked as @Injectable, which allows it to be registered and resolved by the ProviderManager.
@Inject
The @Inject decorator injects dependencies into the constructor of a class-based provider. It tells ProviderManager what dependencies should be resolved when creating a class instance.
@Injectable()
class UserService {
constructor(
@Inject(Logger) private readonly logger: Logger,
@Inject(ConfigService) private readonly configService: Config
) {}
}In this example, the UserService class depends on Logger and ConfigService. The @Inject decorator ensures that when UserService is resolved, Logger and ConfigService will be automatically injected.
Usage
Here’s a basic example that demonstrates how to use ProviderManager to register and resolve different types of providers.
Example: Basic Setup
import { Inject, Injectable, ProviderManager } from '@leandromatos/provider-manager'
// A factory-based provider
type Config = {
appName: string
version: string
}
@Injectable()
const ConfigService = (): Config => ({
appName: 'MyApp',
version: '1.0.0',
})
// A class-based provider
@Injectable()
class Logger {
log(message: string): void {
console.log(`[LOG]: ${message}`)
}
}
// A class-based provider
@Injectable()
class DatabaseConnection {
constructor(private connectionString: string) {}
connect(): void {
console.log(`Connected to database: ${this.connectionString}`)
}
}
// A class-based provider with dependencies
@Injectable()
class UserService {
constructor(
@Inject(Logger) private readonly logger: Logger,
@Inject(ConfigService) private readonly configService: Config
) {}
createUser(name: string): void {
this.logger.log(`Creating user: ${name} for ${this.configService.appName}`)
}
}
// Initialize the ProviderManager
const providerManager = new ProviderManager()Registering Providers
You can register providers using constructors, factories, or string identifiers. Below, we'll demonstrate registering various types of providers:
Class-based Provider
A class-based provider is a simple class that can be instantiated by the ProviderManager.
@Injectable()
class Logger {
log(message: string): void {
console.log(`[LOG]: ${message}`)
}
}
// Register a class-based provider
providerManager.registerProvider(Logger)Factory-based Provider with String Identifier
A factory-based provider is a function that returns an instance of a class or object. You can assign a custom string identifier for later retrieval when using a factory.
@Injectable()
class DatabaseConnection {
constructor(private connectionString: string) {}
connect(): void {
console.log(`Connected to database: ${this.connectionString}`)
}
}
// Register a factory-based provider with a string identifier
providerManager.registerProvider(() => new DatabaseConnection('postgresql://main-database:5432'), 'MAIN_DATABASE')Factory-based Provider without Identifier
You can also register a factory-based provider without using an identifier. In this case, the function itself acts as the identifier.
type Config = {
appName: string
version: string
}
@Injectable()
const ConfigService = (): Config => ({
appName: 'MyApp',
version: '1.0.0',
})
// Register a factory-based provider without an identifier
providerManager.registerProvider(ConfigService)Class-based Provider with Dependencies
When you have a class-based provider that depends on other providers, you can use the @Inject decorator to inject these dependencies.
@Injectable()
class UserService {
constructor(
@Inject(Logger) private readonly logger: Logger,
@Inject(ConfigService) private readonly configService: Config
) {}
createUser(name: string): void {
this.logger.log(`Creating user: ${name} for ${this.configService.appName}`)
}
}
// Register a class-based provider with dependencies
providerManager
.registerProvider(Logger)
.registerProvider(ConfigService)
.registerProvider(UserService)Resolving Providers
Once the providers are registered, you can resolve them through the ProviderManager using either their constructor, factory, or string identifier.
Resolving a Class-based Provider
const logger = providerManager.get(Logger)
logger.log('Hello from Logger')Resolving a Factory-based Provider with String Identifier
const mainDatabaseConnection = providerManager.get('MAIN_DATABASE')
mainDatabaseConnection.connect()Resolving a Factory-based Provider without Identifier
const configService = providerManager.get(ConfigService)
console.log(configService.appName) // Output: MyAppResolving a Class-based Provider with Dependencies
When you resolve a class-based provider with dependencies, the ProviderManager automatically injects the necessary dependencies.
const userService = providerManager.get(UserService)
userService.createUser('John Doe')Example Summary
Here's a summary example that demonstrates registering and resolving multiple types of providers:
const providerManager = new ProviderManager()
providerManager
.registerProvider(Logger) // Class-based provider
.registerProvider(() => new DatabaseConnection('postgresql://main-database:5432'), 'MAIN_DATABASE') // Factory-based provider with identifier
.registerProvider(() => new DatabaseConnection('postgresql://another-database:5432'), 'ANOTHER_DATABASE') // Factory-based provider with identifier
.registerProvider(ConfigService) // Factory-based provider without identifier
.registerProvider(UserService) // Class-based provider with dependencies
// Resolve providers
const logger = providerManager.get(Logger)
const mainDatabaseConnection = providerManager.get('MAIN_DATABASE')
const anotherDatabaseConnection = providerManager.get('ANOTHER_DATABASE')
const configService = providerManager.get(ConfigService)
const userService = providerManager.get(UserService)
// Using resolved services
logger.log('Application started')
mainDatabaseConnection.connect()
anotherDatabaseConnection.connect()
console.log(`App Name: ${configService.appName}`)
userService.createUser('John Doe')API
registerProvider<T>(provider: Constructor<T> | Factory<T>, identifier?: Constructor<T> | string): this
Registers a provider (either a class constructor or a factory) in the ProviderManager.
- provider: The provider to register (constructor or factory).
- identifier: An optional string or constructor to identify the provider. If not provided, the class name is used for constructors.
get<T>(identifier: string | Provider<T>): T
Retrieves a provider instance by its string identifier, constructor, or factory.
- identifier: The identifier (string or provider) to resolve.
License
This project is licensed under the MIT License. See the LICENSE file for details.
