Container API Reference
The Container class provides a dependency injection container for managing multiple DataSource instances with proper async initialization.
Table of Contents
Overview
The Container manages DataSource instances, ensuring:
- Proper async initialization - No race conditions
- Centralized management - Single source of truth
- Status tracking - Know when DataSources are ready
- Error handling - Graceful failure handling
- Bridge connections - Connect DataSources together
import { Container } from 'bindra';
const container = new Container();Constructor
constructor()Creates a new Container instance with no arguments.
Example:
const container = new Container();Methods
register()
Register a new DataSource with the container.
async register<T>(name: string, config: DataSourceConfig): Promise<DataSource<T>>Parameters
- name (
string) - Unique identifier for the DataSource - config (
DataSourceConfig) - Configuration for the DataSource
Returns
Promise<DataSource<T>> - The initialized DataSource instance
Throws
ConfigurationError- If a DataSource with the same name already exists
Example
interface User {
id: number;
name: string;
email: string;
}
// Register a remote DataSource
const users = await container.register<User>('users', {
url: 'https://api.example.com/users'
});
// Register a local DataSource
const products = await container.register('products', {
data: [
{ id: 1, name: 'Product A', price: 100 },
{ id: 2, name: 'Product B', price: 200 }
]
});get()
Retrieve a previously registered DataSource.
async get<T>(name: string): Promise<DataSource<T> | null>Parameters
- name (
string) - The name of the DataSource to retrieve
Returns
Promise<DataSource<T> | null> - The DataSource instance, or null if not found or not ready
Example
// Get a registered DataSource
const users = await container.get<User>('users');
if (users) {
await users.fetch();
console.log(users.data);
}getSync()
Synchronously retrieve a DataSource (only if already initialized).
getSync<T>(name: string): DataSource<T> | nullParameters
- name (
string) - The name of the DataSource to retrieve
Returns
DataSource<T> | null - The DataSource instance, or null if not found or not ready
Example
// Only works if DataSource is already initialized
const users = container.getSync<User>('users');
if (users) {
console.log('Users DataSource is ready');
} else {
console.log('Users DataSource not ready yet');
}has()
Check if a DataSource is registered.
has(name: string): booleanParameters
- name (
string) - The name to check
Returns
boolean - True if registered, false otherwise
Example
if (container.has('users')) {
console.log('Users DataSource is registered');
}getStatus()
Get the initialization status of a DataSource.
getStatus(name: string): 'initializing' | 'ready' | 'error' | nullParameters
- name (
string) - The name of the DataSource
Returns
'initializing'- DataSource is being initialized'ready'- DataSource is ready to use'error'- DataSource failed to initializenull- DataSource not found
Example
const status = container.getStatus('users');
switch (status) {
case 'initializing':
console.log('Loading...');
break;
case 'ready':
console.log('Ready!');
break;
case 'error':
console.log('Failed to initialize');
break;
default:
console.log('Not found');
}initialize()
Initialize all registered DataSources at once.
async initialize(): Promise<void>Returns
Promise<void> - Resolves when all DataSources are initialized
Throws
- Throws if any DataSource fails to initialize
Example
const container = new Container();
// Register multiple DataSources
await container.register('users', { url: '/api/users' });
await container.register('products', { url: '/api/products' });
await container.register('orders', { url: '/api/orders' });
// Initialize all at once
await container.initialize();
// All DataSources are now ready
const users = container.getSync('users');
const products = container.getSync('products');unregister()
Remove a DataSource from the container.
unregister(name: string): booleanParameters
- name (
string) - The name of the DataSource to remove
Returns
boolean - True if removed, false if not found
Example
// Remove a DataSource
const removed = container.unregister('users');
if (removed) {
console.log('Users DataSource removed');
}clear()
Remove all DataSources from the container.
clear(): voidExample
// Clear all DataSources
container.clear();
console.log('All DataSources removed');list()
List all registered DataSource names.
list(): string[]Returns
string[] - Array of DataSource names
Example
const names = container.list();
console.log('Registered DataSources:', names);
// Output: ['users', 'products', 'orders']Usage Examples
Basic Setup
import { Container } from 'bindra';
interface User {
id: number;
name: string;
email: string;
}
interface Product {
id: number;
name: string;
price: number;
}
// Create container
const container = new Container();
// Register DataSources
const users = await container.register<User>('users', {
url: 'https://api.example.com/users'
});
const products = await container.register<Product>('products', {
url: 'https://api.example.com/products'
});
// Use DataSources
await users.fetch();
await products.fetch();Application Initialization
// app.ts
import { Container } from 'bindra';
class Application {
private container: Container;
constructor() {
this.container = new Container();
}
async initialize() {
console.log('Initializing application...');
// Register all DataSources
await this.container.register('users', { url: '/api/users' });
await this.container.register('products', { url: '/api/products' });
await this.container.register('categories', { url: '/api/categories' });
// Initialize all
await this.container.initialize();
console.log('Application initialized!');
}
getDataSource<T>(name: string) {
return this.container.getSync<T>(name);
}
}
// Usage
const app = new Application();
await app.initialize();
const users = app.getDataSource('users');Error Handling
const container = new Container();
try {
await container.register('users', {
url: 'https://invalid-url.example.com/users'
});
} catch (error) {
console.error('Failed to register users DataSource:', error);
// Check status
const status = container.getStatus('users');
console.log('Status:', status); // 'error'
}With Bridge Connections
const container = new Container();
// Register DataSources
const users = await container.register('users', {
url: '/api/users'
});
const orders = await container.register('orders', {
url: '/api/orders'
});
// Create a bridge between users and orders
const bridge = container.createBridge('users', 'orders', {
foreignKey: 'userId',
localKey: 'id'
});
// When a user is selected, orders will automatically filter
users.goto(0);
// orders.data now contains only orders for the selected userStatus Tracking
const container = new Container();
// Register with status tracking
await container.register('users', {
url: '/api/users'
});
// Check if ready before using
const status = container.getStatus('users');
if (status === 'ready') {
const users = container.getSync('users');
await users?.fetch();
} else if (status === 'initializing') {
console.log('Please wait...');
const users = await container.get('users'); // Wait for it
} else if (status === 'error') {
console.error('DataSource failed to initialize');
}Lazy Loading
class DataManager {
private container = new Container();
async getUsersDataSource() {
// Check if already registered
if (!this.container.has('users')) {
await this.container.register('users', {
url: '/api/users'
});
}
return this.container.get('users');
}
async getProductsDataSource() {
if (!this.container.has('products')) {
await this.container.register('products', {
url: '/api/products'
});
}
return this.container.get('products');
}
}Best Practices
1. Use Async Registration
Always use await with register():
// ✅ Good
const users = await container.register('users', config);
// ❌ Bad - May cause race conditions
const users = container.register('users', config); // Missing await2. Initialize Early
Initialize DataSources during app startup:
// ✅ Good - Initialize during app setup
async function initializeApp() {
const container = new Container();
await container.register('users', { url: '/api/users' });
await container.register('products', { url: '/api/products' });
await container.initialize();
return container;
}
const container = await initializeApp();3. Check Status Before Use
Always check if DataSource is ready:
// ✅ Good
const status = container.getStatus('users');
if (status === 'ready') {
const users = container.getSync('users');
// Use users
}
// ❌ Bad - May be null
const users = container.getSync('users');
users.fetch(); // Could throw if users is null4. Handle Errors Gracefully
Wrap registration in try-catch:
// ✅ Good
try {
await container.register('users', config);
} catch (error) {
console.error('Failed to register users:', error);
// Fallback logic
}5. Use TypeScript Generics
Always specify types for type safety:
// ✅ Good
const users = await container.register<User>('users', config);
const user = users.currentRecord.value; // Typed as User | null
// ❌ Bad
const users = await container.register('users', config);
const user = users.currentRecord.value; // Typed as anyRelated Documentation
- DataSource - Main DataSource class
- Getting Started - First steps with Bindra
- Examples - Real-world usage examples